一些奇怪的行为与C#4.0共同支持和反对支持: using System; class Program { static void Foo(object x) { } static void Main() { Action<string> action = _ => { }; // C# 3.5 supports static co- and contravariant method groups // conversions to delegates types, so this is perfectly legal: action += Foo; // since C# 4.0 much better supports co- and […]
好的,我读了一下关于这个话题在stackoverflow,看这个 & 这个 ,但仍然有点混淆共同/反方差。 从这里 协方差允许在原始types仅用于“输出”位置(例如作为返回值)的API中用“较大”(较不具体的)types替代。 反变换允许在原始types仅用于“input”位置的API中replace“更小”(更具体)的types。 我知道它与types安全有关。 关于in/out事情。 我可以说我用什么时候需要写信给它,什么时候只读它。 并in相反方差的方式out 。 但从上面的解释… 在这里 例如, List<Banana>不能被当作List<Fruit>处理,因为list.Add(new Apple())对List是有效的,对于List<Banana>不是。 所以不应该这样,如果我要用来写信给对象,它必须更大一些。 我知道这个问题已经被问到,但仍然非常困惑。
在下面baseElements代码中,我希望能够隐式地从elements转换为baseElements因为TBase可以隐式转换为IBase 。 public interface IBase { } public interface IDerived : IBase { } public class VarianceBug { public void Foo<TBase>() where TBase : IBase { IEnumerable<TBase> elements = null; IEnumerable<IDerived> derivedElements = null; IEnumerable<IBase> baseElements; // works fine baseElements = derivedElements; // error CS0266: Cannot implicitly convert type // 'System.Collections.Generic.IEnumerable<TBase>' to // 'System.Collections.Generic.IEnumerable<IBase>'. // […]
首先,我已经阅读了关于协议和反变换的SO和博客的许多解释,并且非常感谢Eric Lippert在协变和逆变方面创作了这样一个系列。 然而,我有一个更具体的问题,我正试图让我的头稍微有点。 据我所知, 埃里克的解释是,协变和逆变都是描述转换的形容词。 协变变换是保持types顺序的变换,逆变换是逆转变换的变换。 我以这样的方式理解协变性,我认为大多数开发人员直观地理解。 //covariant operation Animal someAnimal = new Giraffe(); //assume returns Mammal, also covariant operation someAnimal = Mammal.GetSomeMammal(); 这里的返回操作是协变的,因为我们正在保持动物比哺乳动物或长颈鹿更大的尺寸。 在这一点上,大多数返回操作是协变的,逆变操作是没有意义的。 //if return operations were contravariant //the following would be illegal //as Mammal would need to be stored in something //equal to or less derived than Mammal //which would mean that […]
我想要一个Covariant集合,其项目可以通过索引检索。 IEnumerable是我知道的唯一一个.net集合,它是Covariant,但是它没有这个索引支持。 具体来说,我想这样做: List<Dog> dogs = new List<Dog>(); IEnumerable<Animal> animals = dogs; IList<Animal> animalList = dogs; // This line does not compile 现在,我知道为什么这是一个问题。 列表实现具有Add方法的ICollection 。 通过向动物的IList投射,它将允许随后的代码添加“真正的” List<Dog>集合中不允许的任何types的动物。 那么是否有人知道一个支持索引查找的集合也是协变的? 我想不创造我自己的。
有人能给我提供简单的C#的例子:协变性,逆变性,不变性和反不变性(如果存在的话)。 我目前看到的所有示例只是将一些对象转换为System.Object 。
为什么呢 val list:List[Any] = List[Int](1,2,3) 工作,但是 val arr:Array[Any] = Array[Int](1,2,3) 失败(因为数组是不变的)。 这个devise决定背后的预期效果是什么?
我开始几个并行的任务,像这样: var tasks = Enumerable.Range(1, 500) .Select(i => Task.Factory.StartNew<int>(ProduceSomeMagicIntValue)) .ToArray(); 然后join Task.WaitAll(tasks); 在最后一行,我得到一个蓝色波浪标记在tasks下,并带有警告信息: 从Task []到Task []的同variables数组转换 写操作可能导致运行时exception。 我明白为什么我会收到这个消息,但有没有办法解决这个问题呢? (例如,像Task.WaitAll()的通用版本?)
如果我有一个协变types参数的通用接口,如下所示: interface IGeneric<out T> { string GetName(); } 如果我定义这个类层次结构: class Base {} class Derived1 : Base{} class Derived2 : Base{} 然后,我可以使用显式的接口实现在一个类上实现接口两次,如下所示: class DoubleDown: IGeneric<Derived1>, IGeneric<Derived2> { string IGeneric<Derived1>.GetName() { return "Derived1"; } string IGeneric<Derived2>.GetName() { return "Derived2"; } } 如果我使用(非generics的) DoubleDown类并将其转换为IGeneric<Derived1>或IGeneric<Derived2>它将按预期方式运行: var x = new DoubleDown(); IGeneric<Derived1> id1 = x; //cast to IGeneric<Derived1> Console.WriteLine(id1.GetName()); //Derived1 […]
我有这样的代码: class RetInterface {…} class Ret1: public RetInterface {…} class AInterface { public: virtual boost::shared_ptr<RetInterface> get_r() const = 0; … }; class A1: public AInterface { public: boost::shared_ptr<Ret1> get_r() const {…} … }; 这段代码不能编译。 在视觉工作室,它引发了 C2555:重写虚函数返回types不同,并且不是协变的 如果我不使用boost::shared_ptr但返回原始指针,代码编译(我明白这是由于在C ++ 协变返回types )。 我可以看到问题是因为Ret1 boost::shared_ptr不是从RetInterface boost::shared_ptr RetInterface 。 但是我想返回Ret1 boost::shared_ptr以供其他类使用,否则我必须在返回后Ret1返回值。 难道我做错了什么? 如果没有,为什么这样的语言 – 在这种情况下,应该可以扩展处理智能指针之间的转换? 有没有一个理想的解决方法?