【发布时间】:2011-03-21 01:45:24
【问题描述】:
在 CLR 第三版中,有一个我似乎无法理解的示例:
Invariant 表示泛型的意思 类型参数不能更改。一世 只显示了不变的泛型类型 本章到目前为止的参数。 n
Contravariant 意味着泛型 类型参数可以从一个类中改变 到从它派生的类。在 C# 中,你 表示逆变泛型类型 in 关键字的参数。
逆变泛型类型参数 只能出现在输入位置 比如方法的参数。 n 协变的意思是泛型的 类型参数可以从一个类中改变 到它的基类之一。在 C# 中,你 表示协变泛型类型 out 关键字 的参数。 协变泛型类型参数可以 仅出现在输出位置,例如 作为方法的返回类型。
然后作者继续举这个例子:
public delegate TResult Func<in T, out TResult>(T arg);
这里,泛型类型参数 T 是 用 in 关键字标记,使其 逆变的;和泛型 参数 TResult 标有 out 关键字,使其成为协变的
这是我在下一页(292)上遇到问题的地方,然后他在使用界面时说相反。
当使用接受泛型参数和返回值的委托时,建议 只要有可能,总是为逆变和协方差指定 in 和 out 关键字, 因为这样做不会产生不良影响,并使您的委托可以在更多场景中使用。 与委托一样,具有泛型类型参数的接口可以将其类型参数设为 逆变或协变。这是一个具有逆变 >generic 的接口示例 类型参数:
public interface IEnumerator<out T> : IEnumerator {
Boolean MoveNext();
T Current { get; }
}
由于 T 是逆变的,因此可以使以下代码编译并运行>成功:
// This method accepts an IEnumerable of any reference type
Int32 Count(IEnumerable<Object> collection) { ... }
...
// The call below passes an IEnumerable<String> to Count
Int32 c = Count(new[] { "Grant" });
在第二个示例中,他使用了 out 关键字 (IEnumerator<out T>),然后将其称为逆变。这是正确的还是我错过了什么。在接口中定义逆变和协变是否有区别? I have been to Oreilly's website regarding this book and this is not listed.
【问题讨论】:
-
需要注意的是,
Delegate.Combine的设计与方差根本不兼容。如果例程有一个委托类型为Action<Cat>的初始空字段,并且它尝试使用Action<Animal>对其进行Combine,则Action<Cat>类型的字段将包含对Action<Animal>的引用。如果然后尝试使用Action<Cat>来Combine,则尝试将失败。因此,可能与Combine一起使用的委托类型不应是协变或逆变的。太糟糕了,委托类型没有定义自己的Combine方法,因为...... -
...方法
Action<Cat>.Combine可以安全地获取Action<Animal>并将其转换为类型Action<Cat>,因为知道这种转换的结果只会被以下代码使用给它一个Cat。
标签: .net covariance contravariance