我试图弄清楚这些词的确切含义,Covariance以及Contravariance在线的几篇文章和关于StackOverflow的问题,从我能理解的,它只是多态的另一个词.
我对上述陈述是否正确?或者我弄错了?
我在外部类中有以下方法
public static void DoStuffWithAnimals(IDictionary<string, Animal> animals)
在我的调用代码中,我已经有了一个Dictionary<string, Lion>对象,但我无法将此作为此方法的参数传递.那么a IDictionary<,>不是逆变的吗?我看不出为什么这不起作用的任何理由.
我能想到的唯一解决方案是:
var animals = new Dictionary<string, Animal>();
foreach(var kvp in lions) {
    animals.Add(kvp.Key, kvp.Value);
}
有没有办法将此字典传递给此方法,而无需创建相同对象的新字典?
编辑:
因为这是我的方法,我知道我在字典中使用的唯一成员是getter TValue this[TKey key],它是一个成员IDictionary<TKey, TValue>,所以在这种情况下,我无法使用'更宽'类型的参数.
C#规范声明参数类型不能同时具有协变性和逆变性.
这在创建协变或逆变接口时很明显,您可以分别使用"out"或"in"来修饰类型参数.没有选项允许同时("outin").
这种限制只是一种语言特定的约束,还是存在更深层次,更基本的理由,这种理由会使你不希望你的类型既有协变性又有逆变性?
编辑:
我的理解是阵列实际上既是协变的又是逆变的.
public class Pet{}
public class Cat : Pet{}
public class Siamese : Cat{}
Cat[] cats = new Cat[10];
Pet[] pets = new Pet[10];
Siamese[] siameseCats = new Siamese[10];
//Cat array is covariant
pets = cats; 
//Cat array is also contravariant since it accepts conversions from wider types
cats = siameseCats; 
我正在Jon Skeet的深度阅读C#.虽然我已经理解了CoVariance和ContraVariance的概念,但我无法理解这一行:
好吧,当SomeType仅描述返回类型参数的操作时,协方差是安全的 - 当SomeType仅描述接受类型参数的操作时,逆变量是安全的.
有人可以用一个例子来解释两者,为什么两者在一个方向都是安全的而不是在另一个方向?
更新的问题:
我仍然不明白给出的答案.我将尝试使用本书中的相同示例来解释我的担忧 - C# In Depth.
它解释了使用以下类层次结构:

COVARIANCE是:尝试转换IEnumerable<Circle>为IEnumerable<IShape>,但是提到这种转换只有在我们从某个方法返回它时执行时才是类型安全的,而当我们将它作为IN参数传递时它不是类型安全的.
IEnumerable<IShape> GetShapes()
{
    IEnumerable<Circle> circles = GetEnumerableOfCircles();
    return circles; // Conversion from IEnumerable<Circle> to IEnumerable<IShape> - COVARIANCE
}
void SomeMethod()
{
    IEnumerable<Circle> circles = GetEnumerableOfCircles();
    DoSomethingWithShapes(circles); // Conversion from IEnumerable<Circle> to IEnumerable<IShape> - COVARIANCE
}
void DoSomethingWithShapes(IEnumerable<IShape> shapes) // Why this COVARIANCE is type unsafe??
{
    // do something with Shapes
}
CONTRA VARIANCE是:尝试转换IEnumerable<IShape>为IEnumerable<Circle>,仅在将其作为IN参数发送时执行时才提及类型安全.
IEnumerable<Circle> GetShapes()
{ …这是我想要创建的简化函数:
static List<object> GetAnonList(IEnumerable<string> names)
{
    return names.Select(name => new { FirstName = name }).ToList();
}
在该代码块中,我得到编译器错误:
错误CS0029无法将类型'System.Collections.Generic.List <>'隐式转换为'System.Collections.Generic.List'
在匿名类型的文档中,它表示匿名类型被视为类型对象.为什么不C#编译器返回List<object>的names.ToList()?  
此外,为什么以下代码不会导致错误?如果List<<anonymous type: string FirstName>>无法转换为List<object>,那为什么可以转换为IEnumberable<object>?
static IEnumerable<object> GetAnonList(IEnumerable<string> names)
{
    return names.Select(name => new { FirstName = name }).ToList();
}
所以我有一个
BaseClass
以及从基类继承的几个子类
ChildClass1
ChildClass2
我有ObservableCollections需要进行排序的子类,我无法创建新的ObservableCollection<ChildClas1>.
所以我写了一个函数
private void Reorder(ObservableCollection<BaseClass>)
{
   //sort the collection in place
}
那我呢 Reorder(ObservableCollection<ChildClass1>)
编译器抱怨它无法转换 
 System.Collections.ObjectModel.ObservableCollection<ChildClass1>为ObservableCollection<BaseClass>
我将把编译器的内容用于它,但是如何在不必为每个子类型重复我的重新排序功能的情况下实现这一点?
鉴于这些接口和类
public interface IFoo { }
public interface IFooWrapper<I> where I : IFoo { }
public class Foo : IFoo { }
public class FooWrapper : IFooWrapper<Foo> { }
为什么这会失败?
IFooWrapper<IFoo> foo = new FooWrapper();
我知道我可以dynamic在这里使用,但真正的问题是:我有一个方法可以接收这些接口的实现,但由于同样的原因它失败了:
严重性代码说明项目文件行抑制状态错误 CS0266 无法将类型“FooWrapper”隐式转换为“IFooWrapper”。存在显式转换(您是否缺少演员表?)
方法签名看起来像
void Register(IFooWrapper<IFoo> foo)
{
}
编译器在该行失败
Register(new FooWrapper());