如何在c#泛型中将子类转换为父类

Val*_*kyi 3 c# generics covariance contravariance

我有一个课程:

class AClass : CClass
class BClass : CClass
Run Code Online (Sandbox Code Playgroud)

我需要在以下代码中使用它们:

POJO 类:

class SomeObject<T> where T : CClass
    T clazz;
    setClass(T clazz){
        this.clazz = clazz;
    .....
Run Code Online (Sandbox Code Playgroud)

控制器类:

class ObjectExecutor{   

    private SomeObject<CClass> someObject;

    public ObjectExecutor execute(SomeObject<CClass> so){
        someObject = so; //exception when so - is the instance of AClass 
        return this;
    }

    public void build(){
        ....
    }
}
Run Code Online (Sandbox Code Playgroud)

所以当我尝试实现它时:

SomeObject<AClass> soA = new....
soA.execute(soA) //exception point
    .build()
Run Code Online (Sandbox Code Playgroud)

结果我得到了异常: can't cast AClass to CClass

所以我需要使用类似的东西:

class ObjectExecutor{   

    private SomeObject someObject; //without <> signature
         ..... ....
Run Code Online (Sandbox Code Playgroud)

但是“c#”编译器不允许这种方式。

如何在“C#”中使用通用扩展?

截图:

我有两个在以下之间扩展的类:

适配器的按钮延伸

界面:

界面

实施:

在此处输入图片说明

以及发生问题的点:1。

班级

2.

在此处输入图片说明

错误:

Arg "1": the type conversion from "MyTest.Terkin.ActionElement<Ranorex.Button>" in "MyTest.Terkin.ActionElement<Ranorex.Adapter>" is impossible (CS1503) - C:\Users\Valeryi\Documents\Ranorex\RanorexStudio\MyTest\Recording1.UserCode.cs:60,23
Run Code Online (Sandbox Code Playgroud)

Gle*_*leb 7

这是方差和协方差的问题

协方差

在评论部分讨论您的问题后,我意识到您需要这里的协方差,因为您分配的派生类比最初指定的更多。Pineapple.Given等待,ActionElement<Adapter>但您正在尝试通过ActionElement<Button>ButtonAdapter. 这意味着我们在这里需要协方差。正如我在评论部分已经告诉您的那样,您可以使用out关键字实现与泛型的协变。请注意,只有接口和委托类型参数可以指定为变体,因此为了实现这一点,我们必须创建一个接口并在我们希望应用协变时使用它。这是代码(我稍微修改了屏幕截图中的代码):

    class Actions { }

    class Adapter { }
    class Button : Adapter { }

    // covariant generic interface
    interface IActionElement<out T> where T : Adapter
    {
        T GetAdapter();
    }
    // covariant generic interface implementation
    class ActionElement<T> : IActionElement<T> where T : Adapter
    {
        T adapter;
        public T GetAdapter()
        {
            return adapter;
        }

        public ActionElement(T adapter)
        {
            this.adapter = adapter;
        }
    }

    class Pineapple
    {
        IActionElement<Adapter> actionElement;
        Queue<Actions> queue;

        // note that I'm using the IActionElement interface here. Not the class that implements the interface like you do
        public Pineapple Given(IActionElement<Adapter> adapter)
        {
            actionElement = adapter;
            queue = new Queue<Actions>();
            return this;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // now it works
            Pineapple pineapple = new Pineapple();
            var pineappleClone = pineapple.Given(new ActionElement<Button>(new Button()));
        }
    }
Run Code Online (Sandbox Code Playgroud)

逆变

反之亦然,当您需要分配比最初指定的更少的派生类时。

    class BaseClass { }
    class DerivedClassA : BaseClass { }
    class DerivedClassB : BaseClass { }

    interface ISomeObject<in T> where T : BaseClass
    {
        void SetClass(T clazz);
    }

    class SomeRealObject<T> : ISomeObject<T> where T : BaseClass
    {
        T obj;

        public void SetClass(T obj)
        {
            this.obj = obj;
        }
    }
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用它:

ISomeObject<DerivedClassA> soA = new SomeRealObject<BaseClass>();
Run Code Online (Sandbox Code Playgroud)