C#如何避免向子类强制转换类型?

4
假设我有一个名为Shape的基类,然后有一些子类,比如圆形和正方形。
接下来我们在另一个类中创建一个名为GetShape的方法:
public Shape GetShape()
{
    return new Circle();  
}

好的,那么这个想法是,我可以传入一个形状类型,然后返回一个强类型的形状子类。上面的例子是真实代码的极度简化,但我认为它能够说明问题。

那么当我调用这个方法时,它会是什么样子呢?

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

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

下面的代码可以正常运行:

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

我对那个类别不是很满意,如何避免使用它并实现一个方法返回基类,以便能够返回任何兼容的子类。

5个回答

5

即使没有反射,您也可以使用泛型来实现此操作。此示例使用T的无参构造函数过滤器(示例已从Adil进行了修改):

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

1
@Jodrell:如果您不介意,因为您删除了您的答案:我在您的答案中的T的过滤器中添加了Shape - Patrick Hofman
1
是的,但shapeCreator.GetShape<Circle>()相对于new Circle()的优势究竟是什么呢?即使在从泛型方法shapeCreator.GetShape<T>()中调用的情况下,它又如何比new T()更好呢? - Kris Vandermotten
@Kris:目前来看没有,但如果该方法进行更通用的初始化,则这是一个不错的解决方案。 - Patrick Hofman

3

按照您的问题描述,我们无法解决您的问题。不过,您提到:

所以我的想法是,我可以传入一个形状类型,然后得到一个强类型的形状子类返回

您是否意味着这样做:

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

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

如果是这样,并且类型在编译时已经静态确定,只需执行以下操作:
var circle = shapecreator.GetCircle();

如果类型在静态上不是已知的,而只能在运行时确定,您需要逻辑来决定调用哪个方法,例如使用if或switch语句。尽管如此,对于强制转换也需要类似的逻辑,因此这并不是真正的劣势。
另一个选择可能是使用抽象工厂设计模式,其中您有一个ShapeFactoryBase类,带有一个虚拟的Shape Create()方法,以及一个派生类CircleFactory从中继承,并覆盖Create()方法。尽管如此,您仍然需要强制转换,并且您仍然需要逻辑来决定要转换成什么类型。

1
你可以使用通用方法在方法调用中传递所需的类型。在该方法中,你可以使用Activator.Createinstance创建被传递类型的对象。 GetShape定义
public T GetShape<T>() where T : Shape
{
    return (T)Activator.CreateInstance(typeof(T));
}

调用 GetShape 函数

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

编辑 您可以使用新约束而无需使用反射来完成。

当您的泛型类创建类型的新实例时,可以将新的约束应用于类型参数,如下例所示:

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

1

不必使用函数,你可以将形状类嵌套在一个名为GetShape的静态类中,并根据需要从该静态类创建新形状。

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


var NewShape = new GetShape.Circle();

然而,如果你不想这样做,我建议使用通用漏洞利用。


0

如果你想要做一些与Circle相关的事情,你必须将其转换为这个特定类型。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接