首页 > 解决方案 > 在 C# 中用泛型理解协变逆变的问题

问题描述

我不明白为什么以下 C# 代码无法编译。

如您所见,我有一个带有IEnumerable<T>参数的静态泛型方法Something(并且T被限制为IA接口),并且该参数不能隐式转换为IEnumerable<IA>.

解释是什么?(我不寻找解决方法,只是为了了解它为什么不起作用)。

public interface IA { }
public interface IB : IA { }
public class CIA : IA { }
public class CIAD : CIA { }
public class CIB : IB { }
public class CIBD : CIB { }

public static class Test
{
    public static IList<T> Something<T>(IEnumerable<T> foo) where T : IA
    {
        var bar = foo.ToList();

        // All those calls are legal
        Something2(new List<IA>());
        Something2(new List<IB>());
        Something2(new List<CIA>());
        Something2(new List<CIAD>());
        Something2(new List<CIB>());
        Something2(new List<CIBD>());
        Something2(bar.Cast<IA>());

        // This call is illegal
        Something2(bar);

        return bar;
    }

    private static void Something2(IEnumerable<IA> foo)
    {
    }
}

Something2(bar)排队的错误:

参数 1:无法从 'System.Collections.Generic.List' 转换为 'System.Collections.Generic.IEnumerable'

标签: c#covariancecontravariance

解决方案


错误消息提供的信息不足,这是我的错。对于那个很抱歉。

您遇到的问题是协方差仅适用于引用类型这一事实的结果。

您现在可能会说“但是IA是引用类型”。是的。但是你没有说T 等于 IA。你说那T实现 IA的类型,值类型可以实现接口。因此,我们不知道协方差是否会起作用,并且我们不允许它。

如果您希望协方差起作用,您必须告诉编译器类型参数是具有class约束和IA接口约束的引用类型。

错误消息确实应该说转换是不可能的,因为协方差需要保证引用类型,因为这是根本问题。


推荐阅读