为什么以下接口声明会产生无效的差异错误?
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
所需的输入。为什么它必须是协变的?
答案 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 大脑受伤的任何事情都应该被视为对其余部分造成重大健康危害。你被警告了。