65.9K
CodeProject 正在变化。 阅读更多。
Home

泛型中的协变和逆变赋值

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.78/5 (4投票s)

2014年9月11日

CPOL
viewsIcon

14116

只是一个快速示例,用于阐明我们可以做什么以及不能做什么

引言

与一些年轻的同事交流时,我意识到协变和逆变的概念往往没有完全被理解。

参考官方文档以获得正确的解释,本技巧仅旨在通过几行简单的代码示例来帮助理解这些概念。事实上,我记得我只有在开始阅读和编写相关代码后,才真正理解了这些概念。

如何操作泛型协变和逆变委托(和接口)

对于以下示例,我们只需要声明两个空类:BaseDerived(其中 Derived 实现 Base)。

class Base {  }

class Derived : Base {  }

我考虑了具有以下委托的赋值:

  • 协变类型参数:Func<out TResult>
  • 逆变类型参数:Action<in T>
  • 同时具有协变和逆变类型参数:Func<in T, out TResult>

请注意,所有示例都使用委托,但**对于接口来说是一样的**。

namespace Bagnasco.Samples.Variance
{
    using System;

    class Base { }

    class Derived : Base { }

    /// <summary>
    /// Sample class just for clarifying variance concepts
    /// (see: http://msdn.microsoft.com/it-it/library/dd799517(v=vs.110).aspx)
    /// </summary>
    class VarianceAssignmentsSample
    {
        public void VarianceSample()
        {
            Base baseInstance = new Base();
            Derived derivedInstance = new Derived();

            //Ok (ordinary polymorphism)
            baseInstance = derivedInstance;

            //Type parameters signature: <out TResult>
            Func<Base> funcThatReturnsBase = () => baseInstance;
            Func<Derived> funcThatReturnsDerived = () => derivedInstance;

            //Ok, mutch like ordinary polymorphism (TResult is covariant)
            funcThatReturnsBase = funcThatReturnsDerived;

            //Not allowed (TResult is more derived in funcThatReturnsDerived and is not contravariant)
            //funcThatReturnsDerived = funcThatReturnsBase;

            //Type parameters signature: <in T>
            Action<Base> actionThatTakesBase = _ => { };
            Action<Derived> actionThatTakesDerived = _ => { };

            //Ok (T is contravariant)
            actionThatTakesDerived = actionThatTakesBase;

            //Not allowed (T is not covariant and is less derived in actionThatTakesBase)
            //actionThatTakesBase = actionThatTakesDerived

            //Type parameters signature: <in T, out TResult>
            Func<Base, Base> functionThatTakesBaseAndReturnsBase = _ => baseInstance;
            Func<Base, Derived> functionThatTakesBaseAndReturnsDerived = _ => derivedInstance;
            Func<Derived, Base> functionThatTakesDerivedAndReturnsBase = _ => baseInstance;
            Func<Derived, Derived> functionThatTakesDerivedAndReturnsDerived = _ => derivedInstance;

            //Ok (TResult is covariant and in functionThatTakesBaseAndReturnsBase is less derived)
            functionThatTakesBaseAndReturnsBase = functionThatTakesBaseAndReturnsDerived;

            //Not allowed
            //(T is not covariant and in functionThatTakesBaseAndReturnsBase is less derived)
            //functionThatTakesBaseAndReturnsBase = functionThatTakesDerivedAndReturnsBase;
            //functionThatTakesBaseAndReturnsBase = functionThatTakesDerivedAndReturnsDerived;

            //Not allowed
            //(TResult is covariant and in functionThatTakesBaseAndReturnsDerived is more derived)
            //functionThatTakesBaseAndReturnsDerived = functionThatTakesBaseAndReturnsBase;            

            //Not allowed
            //(T is contravariant and in functionThatTakesBaseAndReturnsDerived is less derived
            //functionThatTakesBaseAndReturnsDerived = functionThatTakesDerivedAndReturnsDerived;

            //Not allowed
            //(T is contravariant and in functionThatTakesBaseAndReturnsDerived is less derived,
            // TResult is covariant and in functionThatTakesBaseAndReturnsDerived is more derived)
            //functionThatTakesBaseAndReturnsDerived = functionThatTakesDerivedAndReturnsBase;

            //All assignments are allowed
            //(T is contravariant and in functionThatTakesDerivedAndReturnsBase is more derived,
            // TResult is covariant and in functionThatTakesDerivedAndReturnsBase is less derived)
            functionThatTakesDerivedAndReturnsBase = functionThatTakesBaseAndReturnsBase;
            functionThatTakesDerivedAndReturnsBase = functionThatTakesBaseAndReturnsDerived;
            functionThatTakesDerivedAndReturnsBase = functionThatTakesDerivedAndReturnsDerived;

            //Ok (T is contravariant and in functionThatTakesDerivedAndReturnsDerived is more derived)
            functionThatTakesDerivedAndReturnsDerived = functionThatTakesBaseAndReturnsDerived;

            //Not allowed
            //(TResult is covariant and in functionThatTakesDerivedAndReturnsDerived is more derived)
            //functionThatTakesDerivedAndReturnsDerived = functionThatTakesBaseAndReturnsBase;            
            //functionThatTakesDerivedAndReturnsDerived = functionThatTakesDerivedAndReturnsBase;
        }
    }
}

希望这能帮助更好地理解泛型中的协变和逆变。

© . All rights reserved.