将泛型类转换为其继承的类

时间:2018-08-20 14:40:51

标签: c# generics casting

我正在重构具有以下类的旧库:

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

问题来了:新的Template是从Template<double>继承的,因此在这里强制转换不是一个好方法。有没有变通的方法来保持AnotherClassInLibrary向后兼容,而又不会两次重写API()代码?

P.S。我真的希望C#在C ++中有类似typedef的东西。但是the answer is NO

1 个答案:

答案 0 :(得分:0)

即使您的Template类是从Template<double>继承的,也不一样。考虑到您将按照以下方式更改Template的定义:

public class Template : Template<double>
{
    public int AddedMember { get; set; }
}

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

您总是可以将一个类转换为其基类,因为驱动类包含所有基类的成员。因此,不需要显式转换。但是,当您尝试将基类转换为驱动类时,仅当基类变量指向驱动类的实例时,转换才会成功,因此,驱动类的所有成员都存在。如果否,则会在运行时引发InvalidCastException。因此,必须进行显式强制转换(因为使用显式强制转换的指导原则之一是,如果强制转换可能失败,则使用显式强制转换)。

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

Template a = new Template(); 模板b =(模板)a; //没有异常会抛出

最后一个代码将成功,因为变量a指向Template的实例(而不是Template<double>的实例),因此我们确保(在运行时){ {1}}存在,不会发生错误。

编辑:

在您说完您的要求之后,我可以为您提供帮助。你想要什么?您想启用TemplateTemplate的转换-这可以通过user-defined conversions进行。

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

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

Template<double>

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

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