0

Let's say I have this class

public Holder<T> : IHolder
{
    private mystring;
    private myobj;

    public Holder(T obj, string str)
    {
        mystring = str;
        myobj = obj;
    }
}

Then I want to have Holder< T> extend T, so that I can use Holder< T> as I would a normal T. Is there any way of doing this?

So for exampler, I would like Holder< int> to be treated like an int.

Just adding the : T doesn't work, but I was curious if there was another way.

Implicit conversions wouldn't work, as I would like it to be able to go in, for example an IEnumerable< int>

Anders Miltner
  • 253
  • 3
  • 12
  • 1
    Try it and see (it's about 3 keystrokes and will work or result in an applicable error message). However, perhaps an *implicit conversion* to T would work? – user2864740 Oct 31 '13 at 18:32
  • What do you mean "Extend T"? Inherit it? – gunr2171 Oct 31 '13 at 18:32
  • So you want Holder to be treated as an int (for example)? – David Pilkington Oct 31 '13 at 18:32
  • I think if it is an interface it would work fine. – Alexandre Oct 31 '13 at 18:33
  • You can't do `class Holder : T` – Meirion Hughes Oct 31 '13 at 18:33
  • Don't know if this is what you are after, but try out implicit conversions for the class, but that might be hard to do with a generic type. – gunr2171 Oct 31 '13 at 18:33
  • It works in C++ so probably in C# like this `class Foo : T` – 56ka Oct 31 '13 at 18:35
  • What kind of relation is there between Holder and T? `Has a` or `is a`? – Hossein Narimani Rad Oct 31 '13 at 18:35
  • 4
    Answer here : http://stackoverflow.com/questions/1842636/why-cannot-c-sharp-generics-derive-from-one-of-the-generic-type-parameters-like – 56ka Oct 31 '13 at 18:40
  • @56ka C++ Templates are very different from C# generics. C++ Templates replace the type _at compile tine_, while C# generics do so _at run time_. It may seem subtle but it allows you to do more things with C++ templates (because they are built against specific types) that are not possible with Generics, since they must work against any type that meets the generic constraint(s) – D Stanley Oct 31 '13 at 19:14

1 Answers1

4

The way generics are implemented in .NET requires that all Foo<T> must behave largely the same way regardless of T. Among other things, all Foo<T> must have the same members, save only for the fact that members may include T in their definitions. If Foo<T> could inherit from T, knowing what members Foo<T> exposed would require knowing what members T exposed, which could of course be completely different for a Foo<Automobile> and a Foo<Cat>. If one knows that Foo<T> will only be used for types that derive from e.g. Animal, one could define a class Foo<T> : Animal where T:Animal, but that would only allow a Foo<Cat> to be used as an Animal--not as a Cat.

In many cases, however, what is really needed is not a type Foo<T> which actually inherits T, but rather the ability to create an object which mostly behaves like T, but with some differences. The .NET Framework doesn't allow that to be done directly either, but there are some libraries which can auto-generate proxy objects for that purpose. Given an interface and one or more objects, each of which implements some interface members, and which collectively implement all of them, a proxy generator will create (at run time!) a new class which holds references to the supplied objects and implements that interface by creating for each interface method a class method that chains to the corresponding method on one of the passed-in objects.

Note that although the method which creates these new classes will be generic, the classes themselves will not be. It may be that myProxyMaker.Create<IFoo>(IFlyingMammal) returns a proxy8675309 and a myProxyMaker.Create<ISwimmingMammal> returns a proxy24601. Because they are completely different classes, the fact that IFlyingMammal has different members from ISwimmingMammal would pose no problem. The fact that the classes might have ugly machine-generated names wouldn't really matter because one wouldn't be declaring variables of type proxy8675309 or proxy24601, but instead types IFlyingMammal and ISwimmingMammal.

supercat
  • 77,689
  • 9
  • 166
  • 211