为了账号安全,请及时绑定邮箱和手机立即绑定

将泛型类转换为其继承类

将泛型类转换为其继承类

C#
明月笑刀无情 2021-12-05 16:41:09
我正在重构一个旧库,其中包含以下类:public class Template  //Old one{    public double Value { get; set; }}现在最好提供更多的灵活性以允许用户定义Value类型。所以我改成Template了泛型类:public class Template<T>{    public T Value { get; set; }}此更改打破了旧Template类的用法,因此我尝试添加向后兼容性(允许其他人以旧方式使用我的库):public class Template: Template<double> { }但它也需要在库中进行大量更改。特别是在使用旧的地方Template,例如:public class AnotherClassInLibrary<T>{    public Template<T> API() {...}}public class AnotherClassInLibrary : AnotherClassInLibrary<double>{    // This class is also defined for the old way of using the library    public Template API()    {         return base.API();         // Error here: Template<double> cannot be implicitly convert to Template.    }}所以问题来了: newTemplate是从 继承的Template<double>,所以在这里转换不是一个好的/工作实践。有没有办法在AnotherClassInLibrary不重写API()代码两次的情况下保持向后兼容?PS 我真的希望 C# 有类似typedefC++ 的东西。但答案是否定的。
查看完整描述

1 回答

?
慕丝7291255

TA贡献1859条经验 获得超6个赞

即使你的Template类继承自Template<double>,它也不一样。考虑您将更改的定义Template如下:


public class Template : Template<double>

{

    public int AddedMember { get; set; }

}

现在,您尝试执行前面的代码。您正在尝试将具有某些属性的类转换为具有更多属性的类 - 您将访问内存中不正确的位置!


您始终可以将类转换为其基类,因为驱动类包含所有基类的成员。因此,不需要显式转换。但是,当您尝试将基类转换为驱动类时,只有当基类变量指向驱动类的实例时,转换才会成功,因此,驱动类的所有成员都存在。如果否,InvalidCastException则在运行时抛出遗嘱。因此,需要显式转换(因为使用显式转换的准则之一是在转换可能失败时使用显式转换)。


因此,如果您将代码更改为变量 a(类型Template<double>),则转换将成功:


Template<double> a = new Template();

Template b = (Template)a; // No exception will thrown

最后的代码会成功,因为变量a指向的Template(而不是Template<double>)的实例,所以我们确定(在运行时)所有的成员Template都存在并且不会发生错误。


编辑:

你说出你的要求后,我可以帮你。你想要什么?您想启用“模板”到“模板”的转换 - 这可以通过 [用户定义的转换](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions -运营商/转换运营商)。

但是,不允许在驱动类和基类之间进行自定义转换。所以,有两种解决方案:


Template不会继承自Template<double>,如下所示:

    public class Template<T>

    {

        public T Value { get; set; }

    }

    

    public class Template

    {

        public double Value { get; set; }

        

        public static explicit operator Template(Template<double> generic) // Or implicit instead of explicit

        {

            return new Template { Value = generic.Value };

        }

    }


    var generic = new Template<double> { Value = 1234.56 };

    var nongeneric = (Template)generic; // Or Template nongeneric = generic; if the conversion defined as implicit

您不会定义自定义转换,而是定义一个常规方法(我定义了一个构造函数):

    public class Template<T>

    {

        public T Value { get; set; }

    }

    

    public class Template : Template<double>

    {

        public Template(Template<double> generic)

        {

            this.Value = generic.Value;

        }

    }

    

    var generic = new Template<double> { Value = 1234.56 };

    var nongeneric = new Template(generic);


查看完整回答
反对 回复 2021-12-05
  • 1 回答
  • 0 关注
  • 205 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信