简短的回答
您很少需要担心Generic 类型定义中的in 和out 关键字。使用in/out 泛型类型参数定义的类通常会在您使用它时“正常工作”,我敢打赌大多数开发人员永远不会在自己的代码中编写这样的定义。
更长的答案
要获得完整的解释,您应该阅读Covariance and Contravariance 和Variance in Delegates。我的其余答案只是一些说明性示例代码。
为了简化解释,我将通过Action<T>和Func<TResult>分别解释in和out,而不是Func<T,TResult>。
示例均使用以下两个类:
class BaseClass {}
class DerivedClass : BaseClass {}
协方差:out
对于这个例子,我模仿了Func<out TResult>,但删除了out(协方差)修饰符来展示它的效果。协方差允许我们在任何期望返回 BaseType 的函数的地方使用 返回 DerivedType 的函数。
class CovarianceExamples
{
// This is similar to System.Func<out TResult>(), but with covariance removed
delegate TResult InvariantFunc<TResult>();
void InvariantFuncExample()
{
// Ignore the values of these variables; it's the types that are important
InvariantFunc<BaseClass> baseFunc = null;
InvariantFunc<DerivedClass> derivedFunc = null;
baseFunc = baseFunc; // Allowed
baseFunc = derivedFunc; // Not allowed; compile error!
}
void CovariantFuncExample()
{
// Ignore the values of these variables; it's the types that are important
Func<BaseClass> baseFunc = null;
Func<DerivedClass> derivedFunc = null;
baseFunc = baseFunc; // Allowed
baseFunc = derivedFunc; // Allowed
}
}
逆变:in
对于这个例子,我模仿了Action<in T>,但删除了in(逆变)修饰符来展示它的效果。逆变允许我们在任何期望接受DerivedType 的操作的地方使用接受 BaseType 的操作。
class ContravarianceExamples
{
// This is similar to System.Action<in T>(T), but with contravariance removed
delegate void InvariantAction<T>();
void InvariantActionExample()
{
// Ignore the values of these variables; it's the types that are important
InvariantAction<BaseClass> baseAction = null;
InvariantAction<DerivedClass> derivedAction = null;
baseAction = baseAction; // Allowed
derivedAction = baseAction; // Not allowed; compile error!
}
void ContravariantActionExample()
{
// Ignore the values of these variables; it's the types that are important
Action<BaseClass> baseAction = null;
Action<DerivedClass> derivedAction = null;
baseAction = baseAction; // Allowed
derivedAction = baseAction; // Allowed
}
}