Nick Swarr
Nick Swarr

Reputation: 1322

C# Generics and polymorphism: an oxymoron?

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?

Upvotes: 23

Views: 13743

Answers (6)

Manish Basantani
Manish Basantani

Reputation: 17509

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(); }            
}

Upvotes: 5

dreamitcodeit
dreamitcodeit

Reputation: 11

public Class ReflectionReport<T> 
{
    // This class uses Reflection to produce column-based grids for reporting.  
    // However, you need a type in order to know what the columns are. 
}

... so, in another class you have...

public Class ReflectionReportProject {
    ReflectionReport<Thang> thangReport = new ReflectionReport<Thang>(); 
    ReflectionReport<Thong> thongReport = new ReflectionReport<Thong>(); 



    ... some more stuff ...

    // Now, you want to pass off all of the reports to be processed at one time....
    public ReflectionReport<????>[] ProvideReports() 
    {
        return new ReflectionReport<????>[] { thangReport, thongReport } ;
    }
}

Upvotes: 0

Douglas
Douglas

Reputation: 37781

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

Upvotes: 2

supercat
supercat

Reputation: 81347

I think what you're looking for is:

  SomeClass(of someType) someInstance = factory(of someType).Create();
or maybe
  SomeClass(of someType) someInstance = factory.Create(of someType)();
or
  SomeClass(of someType) someInstance = factory.Create();

It's possible to have a set of factory classes to create different generic classes, or to have a factory with a generic type parameter to indicate which generic type it should create (note that in either case, the type parameter is the type parameter for the generic class, rather than being the generic class itself). It's also possible to have a factory which is designed to return instances of one particular form of a generic type.

Upvotes: 0

Matthew Scharley
Matthew Scharley

Reputation: 132524

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.

Upvotes: 11

elder_george
elder_george

Reputation: 7889

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.

Upvotes: 19

Related Questions