c#如何避免类型转换到子类

本文关键字:子类 类型转换 何避免 | 更新日期: 2023-09-27 18:06:06

假设我有一个基类Shape。然后是一些子类,比如circle和square。

让我们在另一个类中创建一个名为GetShape的方法:

public Shape GetShape()
{
    return new Circle();  
}

好的,这个想法是,我可以传入一个shapeType然后得到一个强类型Shape子类返回。上面的例子是对实际代码的大量简化,但我认为它已经表达了重点。

那么当我调用这个方法的时候它看起来会是

var shapeCreator = new ShapeCreator();
Circle myCircle = shapeCreator.GetShape(); 

唯一的问题是它甚至不会运行,因为它需要强制转换。

这将实际工作:

Circle myCircle = (Circle) shapeCreator.GetShape(); 

我对这种强制转换不感兴趣,我如何避免它,并且仍然可以实现一种方法返回基类,以便我可以返回任何兼容的子类。

c#如何避免类型转换到子类

您可以为此使用泛型,即使没有反射。这个示例在T上使用无参数构造器过滤器(从Adil更改的示例):

public T GetShape<T>() where T : Shape, new()
{
    return new T();
}

没有办法解决您的问题。但是,你说

我的想法是,我可以传入一个shapeType然后得到一个强类型type Shape子类返回

你的意思是:

var shape = shapecreator.GetShape(typeof(Circle));

var shape = shapecreator.GetShape<Circle>();

如果是,并且类型在编译时是静态已知的,只需执行

var circle = shapecreator.GetCircle();

如果类型不是静态已知的,但只能在运行时确定,您将需要逻辑来决定调用什么方法,例如使用ifswitch语句。话虽如此,对于强制转换,您也需要这样的逻辑,所以这并不是一个真正的缺点。

另一个选择可能是使用抽象工厂设计模式,其中您有一个ShapeFactoryBase类和一个virtual Shape Create()方法,以及从它继承的派生类CircleFactory,并覆盖Create()方法。但是您仍然需要强制转换,并且您仍然需要逻辑来决定要强制转换为什么类型。

您可以使用泛型方法通过方法调用传递您想要的类型。在这个方法中,你可以使用Activator。创建对象的类型

GetShape定义

public T GetShape<T>() where T : Shape
{
    return (T)Activator.CreateInstance(typeof(T));
}

GetShape的调用

Circle c = GetShape<Circle>();
Rectangle r = GetShape<Rectangle>();

编辑你可以使用new Constraint

不反射

将新约束应用于泛型类的类型参数创建该类型的新实例,如下面的示例所示:

public T GetShape<T>() where T : Shape, new()
{
    return new T();
}

不使用函数,您可以简单地将形状类嵌套在GetShape静态类中,并根据需要从该静态类创建新形状。

public static class GetShape {
    public class Circle() { .. }
    public class Square() { .. }
    public class Triangle() { .. }
    ...
}

var NewShape = new GetShape.Circle();

但是,如果您不希望这样做,我建议使用泛型。

如果你想做一些特定于Circle的事情,你必须转换为这种特定的类型。

您可以使用动态对象,但在这种情况下,您将失去编译阶段的类型安全检查。