C# Generics and polymorphism: an oxymoron?

11,092

Solution 1

As far as I can see, consuming code doesn't need specifics of generic class (i.e., it doesn't depends on what T is). So, why don't you introduce interface that SomeClass<T> will implement, and use instance of this interface.

E.g.:

public interface ISome
{
    void SomeMethod();
}

public class SomeClass<T>: ISome
{
    public virtual void SomeMethod(){ }
}

public void DoSomethingClienty()
{
    Factory factory = new Factory();
    ISome someInstance = factory.Create();

    someInstance.SomeMethod();
}

Now, subclasses of SomeClass<T> can operate differently on different Ts, but consuming code won't change.

Solution 2

I think you are misunderstanding the point of generics. Generics allows you to generalise a class that requires a type, but doesn't particularly care itself what type that is. For instance, a List<string> is a list of strings, but what would a List be? It's a rather useless concept to have a list of nothing.

Each specialised class (ie, List<string>) is it's own distinct type, and the compiler treats it as such. It is possible to get at the generic type itself (typeof(List<>) for instance), but in most cases it's useless, and you certainly can't make an instance of it.

Solution 3

I would prefer using abstract class to act as base of all generic types.

public abstract class SomeClass 
{
    public abstract void SomeMethod();
}

public class SomeClass<T> : SomeClass
{
    public override void SomeMethod() { }            
}

public class DeriveFrom<String> : SomeClass<String>
{
    public override void SomeMethod() { base.SomeMethod(); }            
}

Solution 4

It seems that once you introduce a Generic into an inheritance hierarchy or interface, you can no longer use that family of classes in a polymorphic way

Correct, it's quite similar to this situation:

class StringContainer
{
}

class IntContainer
{
}

StringContainer container = new IntContainer(); // fails to compile

but you could do this:

class Container
{
}

class Container<T> : Container
{
}

Container container = new Container<String>(); // OK
Share:
11,092
Nick Swarr
Author by

Nick Swarr

MOOOO

Updated on June 04, 2022

Comments

  • Nick Swarr
    Nick Swarr almost 2 years

    I just want to confirm what I've understood about Generics in C#. This has come up in a couple code bases I've worked in where a generic base class is used to create type-safe derived instances. A very simple example of what I'm talking about,

    public class SomeClass<T>
    {
        public virtual void SomeMethod(){ }
    }
    
    public class DeriveFrom :SomeClass<string>
    {
        public override void SomeMethod()
        {
            base.SomeMethod();
        }
    }
    

    The problem comes up when I then want to use derived instances in a polymorphic way.

    public class ClientCode
    {
        public void DoSomethingClienty()
        {
            Factory factory = new Factory();
            //Doesn't compile because SomeClass needs a type parameter!
            SomeClass someInstance = factory.Create();
    
            someInstance.SomeMethod();
        }
    }
    

    It seems that once you introduce a Generic into an inheritance hierarchy or interface, you can no longer use that family of classes in a polymorphic way except perhaps internal to itself. Is that true?

  • Nick Swarr
    Nick Swarr over 14 years
    I think this is the best solution. We extend only the interface the client cares about and we hide the generics under the hood.
  • Manish Basantani
    Manish Basantani over 14 years
    Have no idea about the implementation of "Factory" mentioned by Nick. But i am quite sure, it can very well be implemented in the abstract non-generic 'SomeClass'.
  • user1126454
    user1126454 about 12 years
    The above is an example of how polymorphism with generics would be really useful.
  • Elisabeth
    Elisabeth over 11 years
    @Amby But what would you do if the abstract void SomeMethod() has a return type of T and a parameter of type T ? Then you can not hide the generics under your non-generic abstract class. I would appreciate an answer or tip from you :)
  • Servadac
    Servadac about 5 years
    @Elisabeth A lot of time has passed but, have you found out a solution to this approach? I'm dealing with the same problem right now.
  • ricecakebear
    ricecakebear almost 5 years
    @Servadac The reason op tries to use polymorphism is that there is some common functionality independent of type parameters, which dictates there must be a "SomeMethod" with a signature void of type parameters.