如何在 C# 泛型中将子项转换为父项 class

How to cast child to parent class in c# generics

我有一个 classes:

class AClass : CClass
class BClass : CClass

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

POJO class:

class SomeObject<T> where T : CClass
    T clazz;
    setClass(T clazz){
        this.clazz = clazz;
    .....

控制器 class:

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(){
        ....
    }
}

所以当我尝试实现它时:

SomeObject<AClass> soA = new....
soA.execute(soA) //exception point
    .build()

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

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

class ObjectExecutor{   

    private SomeObject someObject; //without <> signature
         ..... ....

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

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

截图:

我有两个 classes 在之间延伸:

接口:

实施中:

以及发生问题的地方: 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

variances and covariances

的事情

Covariance

在评论部分讨论了您的问题后,我意识到您需要此处的协方差,因为您分配的 class 比最初指定的要多。 Pineapple.Given 等待 ActionElement<Adapter> 但您正在尝试传递 ActionElement<Button> 并且 Button 派生自 Adapter。这意味着我们在这里需要协方差。正如我在评论部分告诉你的那样,你可以使用 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()));
        }
    }

Contravariance

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

    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;
        }
    }

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

ISomeObject<DerivedClassA> soA = new SomeRealObject<BaseClass>();