接口方法中与委托的方差无效

时间:2017-08-29 17:22:54

标签: c# c#-4.0

为什么以下接口声明会产生无效的差异错误?

public interface ICache<in TKey, TValue>
{
  TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory);
}

编译器说:

  

错误CS1961无效方差:类型参数'TKey'必须在'ICache&lt; TKey,TValue&gt; .GetOrAdd(TKey,Func&lt; TKey,TValue&gt;)'上协变有效。 'TKey'是逆变的。

问题在于TKey参数中使用Func。但是TKey被用作Func所需的输入。为什么它必须是协变的?

1 个答案:

答案 0 :(得分:4)

TL; DR:C#编译器确保您的安全。

实际上,&#34;输入位置的嵌套输入会产生输出&#34;当涉及到泛型方差时。您的方法有一个本身接受TKey的参数,这种参数可以反转方差。

最容易理解为什么它被禁止通过想象它是否被允许。然后你可以写:

public class ObjectKeyedCache : ICache<object, object>
{
    public object GetOrAdd(object key, Func<object, object> valueFactory)
    {
        // Let's ignore the specified key, and just pass in an object!
        return valueFactory(new object());
    }
}

然后你可以写:

ICache<object, object> objectKeyedCache = new ObjectKeyedCache();
// Ah, due to contravariance, this should be okay...
ICache<string, object> stringKeyedCache = objectKeyedCache;

// Okay, this is a weird cache function, but bear with me
stringKeyedCache("key", text => text.Length);

然后尝试将object引用传递给从lambda表达式Func<string, object>创建的text => text.Length。砰!

有关更多详细信息,请阅读Part 5 of Eric Lippert's variance blog series。这是该帖子中最重要的部分:

  

这样做会让我的大脑受到伤害,但这也会塑造角色,所以我们走了!

使 Eric 大脑受伤的任何事情都应该被视为对其余部分造成重大健康危害。你被警告了。