Daniel Dawes
Daniel Dawes

Reputation: 1005

Generics - Using parent class to specify type in generics

I am looking at some covariance/contravariance stuff, I have a much wider question but it all boils down to this:

GenericRepository<BaseEntity> repo = new GenericRepository<ProductStyle>(context);

This doesn't work, even though BaseEntity is the parent abstract class of ProductStyle, is there a way of achieving this?

Upvotes: 8

Views: 146

Answers (2)

David Hoerster
David Hoerster

Reputation: 28701

I'm just wondering if something like this would also be useful -- using a restriction on the definition of your GenericRepository limiting the base type that T can be:

void Main()
{
    var repo = new GenericRepository<ProductStyle>(new ProductStyle());
    Console.WriteLine(repo.ToString());  //just output something to make sure it works...
}

// Define other methods and classes here
public class GenericRepository<T> where T : BaseEntity {
    private readonly T _inst;

    public GenericRepository(T inst){
        _inst = inst;
        _inst.DoSomething();
    }
}

public class BaseEntity {
    public Int32 Id {get;set;}

    public virtual void DoSomething() { Console.WriteLine("Hello"); }
}

public class ProductStyle : BaseEntity {
}

So if you have a GetRepo<T> method, that method could return a GenericRepository of T, and you're assured that T is a child of BaseEntity.

Upvotes: 0

Marc Gravell
Marc Gravell

Reputation: 1062705

The only way of doing that is with an out generic restriction (which will make it hard to save objects, but fine to retrieve them), on an interface (not a class). If you have:

interface IGenericRepository<out T> {...}

then an IGenericRepository<ProductStyle> can be assigned to a variable of type IGenericRepository<BaseEntity>, since all ProductStyle are also BaseEntity, and we have restricted ourselves to covariant / out usage:

IGenericRepository<BaseEntity> tmp = GetRepo<ProductStyle>(context);
// note that the right-hand-side returns IGenericRepository<ProductStyle>
...
private IGenericRepository<T> GetRepo(...) {...}

Note, however, that this covariant / out usage makes it impossible to do things like:

interface IGenericRepository<out T>
{
    T Get(int id); // this is fine, but:
    void Save(T value); // does not compile; this is not covariantly valid
}

Upvotes: 6

Related Questions