Home > Mobile >  Would like to return different classes from a single generic method call without using object
Would like to return different classes from a single generic method call without using object

Time:02-13

I have three classes--very simple example:

    public class MyTableLayoutPanelBase : TableLayoutPanel
    {
    }

    public class MyTableLayoutPanelExt : MyTableLayoutPanelBase
    {
    }

    public class MyTableLayoutPanelUltraExt : MyTableLayoutPanelExt
    {
    }

The Base subclass subclasses the Microsoft WinForms TableLayoutPanel control. I then have an Ext version that further subclasses my Base class and an UltraExt that subclasses the Ext class. In my real-world use, the Base, Ext, and UltraExt subclasses add some properties beyond what was inherited. For the sake of this discussion, all of these classes have the same implementation...

What I'd like is a factory that returns one of these subclassed objects. The approach I took was to do this:

    public static object CreateMyTableLayoutPanelControl<T>() 
    {
        if (typeof(T) == typeof(MyTableLayoutPanelControlBase))
        {
            return new MyTableLayoutPanelControlBase();
        }
        if (typeof(T) == typeof(MyTableLayoutPanelControlExt))
        {
            return new MyTableLayoutPanelControlExt();
        }
        if (typeof(T) == typeof(MyTableLayoutPanelControlUltraExt))
        {
            return new MyTableLayoutPanelControlUltraExt();
        }
    }

This lets me do something like this:

var myTableLayoutPanelControlExt = (MyTableLayoutPanelExt)CreateMyTableLayoutPanelControl<MyTableLayoutPanelExt>();

The problem is that I need to cast the object returned to the subclass type I need--I know the cast will succeed as long as I cast to one of the three types I know CreateMyTableLayoutPanelControl will return. But that's kludgy, and expensive. I'd much rather just receive from the factory the actual object in the correct type I need.

Is there a way I can leverage the generics and the fact that my classes don't implement an interface to return not object but the actual class instance requested in the CreateMyTableLayoutControl generics call? Ideally, I'd like this code to work without casts:

MyTableLayoutPanelExt myTableLayoutPanelControlExt = CreateMyTableLayoutPanelControl<MyTableLayoutPanelExt>();

CodePudding user response:

You could do this in two steps:

First, create a non-generic method using a Type parameter doing the heavy lifting:

public static MyTableLayoutPanelBase CreateMyTableLayoutPanelControl(Type t)
{
    if (t == typeof(MyTableLayoutPanelBase))
    {
        return new MyTableLayoutPanelBase();
    }
    if (t == typeof(MyTableLayoutPanelExt))
    {
        return new MyTableLayoutPanelExt();
    }
    if (t == typeof(MyTableLayoutPanelUltraExt))
    {
        return new MyTableLayoutPanelUltraExt();
    }
    return null;
}

Then, you can easily provide a generic version doing the cast for you:

public static T CreateMyTableLayoutPanelControl<T>() where T : MyTableLayoutPanelBase
{
    return (T)CreateMyTableLayoutPanelControl(typeof(T));
}

CodePudding user response:

You can try to use Activator.CreateInstance function with generics, then let generics type make constract with TableLayoutPanel your base Type TableLayoutPanel

public static T CreateMyTableLayoutPanelControl<T>() 
    where T : TableLayoutPanel
{
    return Activator.CreateInstance<T>();
}

I would not return object type from the method unless necessary, because it will cause some problems.

c# fiddle

  • Related