C# how to avoid typecasting to subclass?

448 Views Asked by At

Let's say I have a base class called Shape. And then some sub classes such as circle and square.

Let's then create a method in another class called GetShape:

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

Alright, so the idea is, that I can pass in a shapeType and then get a strongly typed Shape subclass returned. The above example is a massive simplification of real code, but I think it gets the point across.

So how when I call this method it would look like

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

Only problem is it won't even run, since it requires a cast.

This would actually work:

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

I'm not wild about that cast, how can I avoid it and still accomplish a way to have a method return a baseclass so that I can return any compatible subclass.

5

There are 5 best solutions below

3
On BEST ANSWER

You can use generics for this, even without reflection. This sample uses the parameterless constructor filter on T (sample altered from Adil):

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

If you want to do something Circle-specific you must cast to this particular type.

You could use dynamic objects but in such case you lose type safty checks on compilation stage.

0
On

You can use generic methods to pass the type you want with the method call. In the method you can use Activator.Createinstance to create the object of type being passed.

GetShape Definition

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

Calling of GetShape

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

Edit You can do it without reflection using new Constraint

Apply the new constraint to a type parameter when your generic class creates new instances of the type, as shown in the following example:

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

There is no way to solve your problem as presented. However, you say

so the idea is, that I can pass in a shapeType and then get a strongly typed Shape subclass returned

Do you mean something like this:

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

or

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

If so, and the type is statically known at compile time, just do

var circle = shapecreator.GetCircle();

If the type is not statically known, but can only be determined at runtime, you will need logic to decide what method to call, e.g. using if or switch statements. That being said, you need logic like that for a cast as well, so this isn't a real disadvantage.

Another option may be to use an abstract factory design pattern, where you have a ShapeFactoryBase class with a virtual Shape Create() method, and a derived class CircleFactory that inherits from it, and overrides the Create() method. You would still need the cast though, and you would still need logic to decide what type to cast to.

0
On

Instead of using a function, you could simply nest the shape classes in a GetShape static class and create the new shape from that static class as needed.

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


var NewShape = new GetShape.Circle();

However, I do recommend the generics exploit if you don't wish to do this.