【问题标题】:It's possible pass subclass of superclass in <T>?<T> 中是否可以传递超类的子类?
【发布时间】:2012-03-27 03:13:29
【问题描述】:

我有一个名为 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>();
        }
    }
}

【问题讨论】:

    标签: c# oop nhibernate polymorphism


    【解决方案1】:

    简而言之,你不能,真的。但是,如果您使用非泛型的基本接口,或者使用 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 对象。

    【讨论】:

      【解决方案2】:

      你的尝试不起作用是一件好事,如果它起作用了,你会引入一个错误。

      假设我有 ab 类型的变量 EmpresaDaoa 使用 Empresa 父级初始化,b 使用 Assessoria 父级初始化。由于ab 属于同一类型,因此应该可以在任何地方使用一个代替另一个。假设Assessoria 但不是Empresa 有一个方法assess()。但是你希望b.parentAssessoria,所以你想调用b.parent.assess() 但你不能调用a.parent.assess() 这意味着ab 首先不应该是同一类型。

      解决方案取决于您是否会致电.parent.assess()

      a) 如果您永远不会在EmpresaDao 类中调用.parent.assess(),则让父类的编译时间类型始终为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”和“@987654352 @holding EmpresaDao" 应该是两个不同的类。 (可能实现相同的接口)

      编辑:现在我意识到,在我的解决方案中,我错误地使用了父 Empresa 或 Assessoria 的类型,而不是 GenericDao 或 GenericDao。我相信我的 main 仍然有效。

      【讨论】:

        猜你喜欢
        • 2019-08-28
        • 2017-11-02
        • 2015-08-02
        • 1970-01-01
        • 2019-09-20
        • 1970-01-01
        • 1970-01-01
        • 2020-09-23
        • 2018-02-03
        相关资源
        最近更新 更多