generic inheritance in C#?

44,979

Solution 1

This is not possible, because depending on what type T is, the public interface of MyGenericClass would change.

If you have lots of different classes that all expose the same interface, you could declare MyGenericClass to expose that interface, and in the implementation of all of the functions delegate the calls to obj

Solution 2

The specific question, why can't you do this:

public class MyGenericClass<T> : T

And you can do this:

public class MyGenericClass<T> 
{
   T obj;
}

The reason is that the CLR likes to be able to compile a single version of the code for MyGenericClass that will work for any reference type specified for T.

It can do this for the second case, because it can quietly replace T with object and insert appropriate casts, roughly equivalent to:

public class MyGenericClass 
{
   object obj;
}

But for the inheritance version, that trick doesn't work.

Also, many useful facilities would be impossible to describe through interface constraints. When you inherit from a type, you can do a lot more than just call methods on it - you can override them as well. Consider this hypothetical example:

class MyBase 
{
    public virtual void MyVirtual() { }
}

class MyGenericDerived<T> : T
{
    public override void MyVirtual() 
    {
        Console.WriteLine("Overridden!"); 
    }
} 

MyBase obj = new MyGenericDerived<MyBase>();
obj.MyVirtual();

What I want to do there is something like a "mix-in", where MyGenericDerived supplies definitions for virtual functions in whatever base it is applied to. But how does the compiler know that T will have a method called MyVirtual that can be overridden? I'd need to put a constraint on T. How would I express that through interfaces? It's impossible. Using interfaces to describe constraints isn't an adequate solution once you allow inheritance from type parameters. So that's another reason why it doesn't exist in the language today.

Solution 3

You could do something like

public interface IXyzable { void xyz(); }

public class MyGenericClass<T> : IXyzable where T : IXyzable {
    T obj;
    public void xyz() {
        obj.xyz();
    }
}

Edit: Now I understand the question

Solution 4

You'll need all your possible T's to implement some interface so that you know that obj.XYZ() makes sense, then you can do

public interface Ixyz
{
    void XYZ();
}

public class MyGenericClass<T> : Ixyz where T:Ixyz, new()
{
    T obj;

    public MyGenericClass()
    {
        obj = new T();
    }

    public void XYZ()
    {
        obj.XYZ();
    }
}

I've made MyGenericClass implement Ixyz too since it obviously does expose the right method, but maybe that's best left out since it allows

var x = new MyGenericClass<MyGenericClass<SomeClass>>();

which is unlikely to ever be a good idea.

Solution 5

This is pretty much duck-typing, but you could use reflection. When you create the generic class with a reference to the obj, use reflection to try and find a method with the right signature. As long as you store a reference to the method, performance won't be too bad.

class BaseGeneric<T>
{
    private T obj;
    private MethodInfo mi;
    private const string MethodNameOfInterest = "Xyz";

    public BaseGeneric(T theObject)
    {
        this.obj = theObject;
        Type t = obj.GetType();
         mi = t.GetMethod(MethodNameOfInterest);
    }

    public void Xyz()
    {
        mi.Invoke(obj, null);
    }
}   

Of course, you would need to add a lot more for error checking and such, but that is the gist of what you could do. Also, don't forget to add the System.Reflection namespace to your using clause.

Share:
44,979
Admin
Author by

Admin

Updated on August 12, 2020

Comments