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

标签 c# generics covariance contravariance

我有一个类:

class AClass : CClass
class BClass : CClass

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

POJO 类:

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

Controller 类:

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()

结果我得到异常:无法将 AClass 转换为 CClass

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

class ObjectExecutor{   

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

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

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

截图:

我有两个类在它们之间延伸:

Button extend of Adapter

接口(interface):

Interface

实现:

enter image description here

以及发生问题的地方: 1.

class

2.

enter image description here

错误:

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

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

    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 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>();

关于c# - 如何在 C# 泛型中将子类转换为父类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59226406/

相关文章:

c# - protobuf-net 如何序列化 DateTime?

c# - 在Unity中,如何使用脚本访问预制件的子组件?

typescript - 命名泛型函数的返回类型

swift - 有什么方法可以快速为通用参数分配默认值吗?

go - 为什么我不能在 Go 中用一种类型的 slice 替换另一种类型?

c# - 拦截请求并向 Xamarin.Forms.WebView 提供资源

c# - 使用 Darren Johnstone 的大文件上传库和 ASP.NET MVC Controller

scala - Shapeless 在通用上下文中不起作用

scala - 涉及带有通配符的类型参数的奇怪编译错误