views:

780

answers:

7

I can do

public class MyGenericClass : DL
//but i cannot do
public class MyGenericClass <T> : T

How would i do the second? if i cannot do that, how can i do something like

public class MyGenericClass <T> 
{
    T obj;
    //have all MyGenericClass.XYZ call obj.XYZ
}
+9  A: 

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

Jason Coyne
But in the second case, where T is used to declare a member, that member could be public, and then the public interface of MyGenericClass would change depending on the type of T.
Daniel Earwicker
Just the datatype of the property, which is inherently handled by .net and generics. My point was more that entire functions and properties would be added and removed if it worked the way he wanted, not jsut a datatype change
Jason Coyne
That's circular: "inherently handled by generics" - why doesn't it inherently handle the case that doesn't work? :)
Daniel Earwicker
Its not up to me what they support and what they don't. Although I will note that several of the other answers indicate some of the problems that would cause.
Jason Coyne
No problem - just thought you might want to improve your answer. At the moment, it gives the wrong reason ("the public interface").
Daniel Earwicker
+1  A: 

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

erikkallen
A: 

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.

stevemegson
A: 

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.

Erich Mirabal
why the down vote? I answered the question, didn't I? I would not recommend doing it, but it does solve his problem: BaseGeneric<T>.Xyz() calls the underlying object's Xyz() method no matter what that type is.
Erich Mirabal
Your solution has all the downsides of reflection, and no benefits of duck typing. The external object (BaseGeneric) must have all of the functions declared on it. If you know those functions, just call the same function?
Jason Coyne
It caches the MethodInfo, so the performance penalty is reduced. It looks like the underlying object - so it quacks. It does make him implement each method all over again, so that is the biggest downside. However, T could be anything that implements Xyz, which comes in handy in certain scenarios.
Erich Mirabal
If you make him implement the method manually, then why not just call the implementing method directly? Why use reflection at all? That was the source of the down vote
Jason Coyne
Yeah, you are right. I appreciate the explanation. The only upside to my method is that T could be any class that has the method Xyz. This is handy iff there is no access to the code and can't make it use interfaces. Very limited use, but similar to the upcoming dynamic type in C# 4.0.
Erich Mirabal
+1  A: 

The .NET type system won't allow type declarations of the form you're attempting. One reason why this is disallowed should be intuitive: how would MyGenericClass<T> act when T is a sealed class (e.g. System.String)?

If you absolutely need this functionality (and you know that the type T you'll be using isn't sealed), you can generate proxies at runtime using the classes in the Reflection.Emit namespace. It may also be possible to achieve this effect using AOP tools like PostSharp.

kvb
MyGenericClass<string> would produce a compiler error. If this language feature was available, inheriting from T would automatically constrain T to be unsealed. Although this is only part of the problem (see my answer).
Daniel Earwicker
A: 

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.

Daniel Earwicker
A: 

What about this:

   class BaseClass<T>
    {
       public T property { get; set; }
    }

    class GenericClass<T> : BaseClass<T>
    { 

    }

class Program
{
    static void Main(string[] args)
    {

        GenericClass<int> l = new GenericClass<int>();
        l.property = 10;
    }
}

This achieves what you want to do?

MRFerocius
I don't think so. He wants GenericClass<T> to expose all the methods of T without re-implementing anything. At least, that's my best guess as to what he is asking.
Erich Mirabal