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



我正在用下面这样的类重构一个旧库:

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()代码?

附言我真的希望 C# 在 C++ 中具有类似typedef的东西。但答案是否定的。

即使您的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://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/statement-expressions-operator/conversion-operator(来实现。但是,不允许在驱动类和基类之间进行自定义转换。因此,有两种解决方案:

  1. 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
  1. 您不会定义自定义转换,而是定义一个常规方法(我定义了一个构造函数(:
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);

最新更新