Is it possible to pass a subclass of a superclass to <T>?

I have a class named GenericDao

internal class GenericDao<T> : IGenericDao<T> {
}

      

Two classes of objects:

public class Empresa {
}

public class Assessoria : Empresa {
}

      

And I have one EmpresaDao:

public class EmpresaDao {

    private GenericDao<Empresa> parent { get; set; }

    public EmpresaDao() {
        this.parent = new GenericDao<Empresa>();
    }
}

      

How do I instantiate GenericDao using Assessoria subclass? I am doing something like this but not working:

public class EmpresaDao {

    private GenericDao<Empresa> parent { get; set; }

    public EmpresaDao(Type type) {
        if (type == typeof(Assessoria)) {
            this.parent = new GenericDao<Assessoria>();
        } else {
            this.parent = new GenericDao<Empresa>();
        }
    }
}

      

+3


source to share


2 answers


In short, you can't, really. However, you can cheat a little if you are using a base interface that is not generic, or you are using C # 4 and are using a base interface that is generic but with a covariant or contravariant (depending on the type) type parameter. For the first case:

interface IGenericDaoBase {
}

interface IGenericDao<T> : IGenericDaoBase {
}

public class EmpresaDao {
    private IGenericDaoBase parent { get; set; }
    public EmpresaDao(Type type) {
        // same as before
    }
}

      

Admittedly, it would be better to rethink your design. Perhaps EmpresaDao can take the generic parameter itself to be used like this:



public class EmpresaDao<T> where T : Empresa {
    private GenericDao<T> parent { get; set; }
    public EmpresaDao() {
        this.parent = new GenericDao<T>();
    }
}

      

EDIT: Actually, the more I think about it, the more I believe this last solution is the way to go. The type parameter in the constructor serves the same role as the type parameter in the class signature. This way, you don't have to change your calling code much, except to pass a generic parameter instead of a Type object.

+2


source


Good thing your attempt doesn't work, you would submit an error if it did.

Suppose I have variables a

, b

both types EmpresaDao

. a

is initialized by the parent Empresa

and b

initialized by the parent Assessoria

. Since a

and b

are of the same type, it can be used anywhere except another. Suppose, Assessoria

but doesn't Empresa

have a method assess()

. But you expect it to b.parent

be Assessoria

, so you want to call b.parent.assess()

, but you can't call a.parent.assess()

which means a

and b

shouldn't be of the same type in the first place.

The solution depends on whether you ever call .parent.assess()

:

a) If you never call .parent.assess()

in a class EmpresaDao

, let the parent generation time type always be Empresa

. Here's the solution:

public class EmpresaDao
{
    private Empresa parent {get; set; }
    public EmpresaDao(Func<Empresa> parentConstructor)
    {
        this.parent = parentConstructor();    
    }
}    
static main()
{
    var withEmpresaParent = new EmpresaDao(() => new Empresa());
    var withAssessoriaParent = new EmpresaDao(() => new Assessoria());
    ..
}

      



b) You sometimes call .parent.assess()

inside the EmpresaDao class. Then you have to create a generic EmpresaDao image as @siride said:

public class EmpresaDao<T> where T : Empresa
{
    private T parent {get; set;}
}

      

However, you still have to do runtime checks on the parent before calling .parent.assess()

which means there is still something wrong with your design. But there is not enough information to decide what. Maybe the method .assess()

should be private and not called externally (ie it Assessoria

should be a decorator on a Empresa

: subclass, but with the same interface) Perhaps " Empresa

hold EmpresaDao

" and " Assessoria

hold EmpresaDao

" should be two different classes. (possibly implementing the same interface)

Edit: I now realize that in my solution I mistakenly made the parent type Empresa or Assessoria instead of GenericDao or GenericDao. I believe my main function is still valid.

+1


source







All Articles