可以在<t>?</t>中传递超类的子类

时间:2012-03-09 16:56:24

标签: c# oop nhibernate polymorphism

我有一个名为GenericDao的类

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

两类对象:

public class Empresa {
}

public class Assessoria : Empresa {
}

我有一个EmpresaDao:

public class EmpresaDao {

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

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

如何使用子类Assessoria实例化GenericDao?我这样做了,但没有工作:

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

2 个答案:

答案 0 :(得分:2)

总之,你不能,真的。但是,如果使用非通用的基本接口,或者使用C#4并使用通用的基本接口,但具有协变或逆变(根据需要)类型参数,则可以作弊。对于第一种情况:

interface IGenericDaoBase {
}

interface IGenericDao<T> : IGenericDaoBase {
}

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

不可否认,重新考虑您的设计可能会更好。也许EmpresaDao可以采用一个通用参数本身,可以这样使用:

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

编辑:事实上,我越是想到它,我越相信后一种解决方案就是要走的路。构造函数中的type参数与类签名上的type参数具有相同的作用。因此,除了传入泛型参数而不是Type对象之外,您不必更改调用代码。

答案 1 :(得分:1)

你的尝试不起作用是件好事,如果有的话,你会引入一个bug。

假设我有a类型的变量bEmpresaDao。使用a父级启动Empresa,并使用b父级初始化Assessoria。由于ab属于同一类型,因此应该可以在任何地方使用一个代替另一个。假设Assessoria但不Empresa有方法assess()。但您希望b.parentAssessoria,因此您需要致电b.parent.assess(),但无法致电a.parent.assess(),这意味着ab不应该首先是相同类型的。

解决方案取决于您是否会拨打.parent.assess()

a)如果你永远不会在.parent.assess()类中调用EmpresaDao,那么让父编译的时间类型始终为Empresa。这是一个解决方案:

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)您有时会在EmpresaDao课程中拨打.parent.assess()。那么你应该让EmpresaDao变得通用,就像@siride说的那样:

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

但是,仍然需要在调用.parent.assess()之前对父进行运行时检查。这意味着您的设计中仍然存在问题。但是没有足够的信息来决定什么。也许.assess()方法应该是私有的,不能从外部调用(即Assessoria应该是Empresa上的装饰器:子类但具有相同的接口)也许“Empresa持有EmpresaDao“和”Assessoria持有EmpresaDao“应该是两个不同的类别。 (可能实现相同的接口)

编辑:现在我意识到,在我的解决方案中,我错误地将父Empresa或Assessoria的类型改为GenericDao或GenericDao。我相信我的主要仍然有效。