【问题标题】:How to dynamically instantiate a more specific type in a linq query如何在 linq 查询中动态实例化更具体的类型
【发布时间】:2012-12-06 15:34:29
【问题描述】:

我有一个 linq 查询,它当前正在基于泛型类型参数进行对象实例化。我实际上需要实例化泛型参数的更具体的子类。有没有办法用派生类型进行实例化?如有必要,我愿意使用反射甚至直接 IL 发射,但如果可能的话,我想尝试对基类的属性进行类型检查。

所以我的代码是这样的:

IQueryable<TType> myObjects = from blah in blahblah
                              select new TType
                              {
                                   PropertyA = someValue;
                                   PropertyB = someOtherValue;
                              }

但我需要 IQueryable 中的对象实际上是 TType 的派生类。我事先不知道它们将是哪个派生类,只是它们都是基于其他逻辑的相同派生类型。

【问题讨论】:

  • TType 是实际类型还是模板参数?如果是模板参数,可以在TType上添加约束吗?
  • TType 是包含该方法的类的泛型类型参数。代码的目标是从通用基本类型生成上下文特定实体。我们只能在编译时保证它将是抽象公共类型的某种派生。
  • 如何在编译时保证?是否有任何限制或可能是任何类型?例如,会不会是int
  • 函数的一个参数是否可以是一个Func&lt;TType&gt; constructor,它返回一个新构造的对象,它是某种类型的TType?然后你可以传入从()=&gt; new ConcreteType()() =&gt; MyFactory.Create(...) 的任何东西。
  • @DStanley-TType 被限制为抽象的公共基本类型。

标签: c# linq reflection instantiation


【解决方案1】:

听起来你需要一个工厂模式:

from blah in blahblah
select BaseTypeFactory.Create(/* parameters/objects necessary to create the BaseType*/)

BaseTypeFactory 然后会做它需要做的任何事情来吐出正确的派生BaseType 实例。

如果(如您的 cmets 所说)TType 被限制为特定的基本类型,则工厂可能看起来像:

(假设TTypewhere TType : BaseType 约束)

public void BaseType TTypeFactory.Create(/* parameters/objects needed to create Base Types*/)
{
    // full of assumptions, modify to fit your needs:
    switch( typeID /*or some othervariable designating type to create*/)
    case 1: // DerivedType 1
        return new DerivedType1 { /* initialization parameters */ };
        break;
    case 2:
        return new DerivedType2 { /* initialization parameters */ };
        break;
    // etc.

}

【讨论】:

  • 但由于 TType 是一个泛型参数,而不是已知的编译时类型,因此无法确保它具有静态 Create 方法。
  • 是的,我也一直在朝着这个方向努力。诀窍是特定构造特定于给定的 LINQ 查询,并且确定适当的类型需要一个反射调用,我试图避免最终用户必须编写该调用。我也许可以让他们使用基本构造,然后在返回给他们的对象上设置他们需要的值。
  • @Servy - 因为我知道 TType 必须是特定类型的派生,所以我可以让它为该基本类型调用工厂并完全忽略泛型参数。我会知道工厂总是会产生 TType 的派生类,因此我应该安全地将结果转换回 TType 从而满足通用约束。至少我认为这会奏效。
  • @AJHenderson 我认为TType 是基本类型,而不是派生类型。如果它是派生类型,为什么不能只使用 OP 中的代码并添加 where T : new() 子句?
  • @Servy - 你是对的,TType 是基本类型。但我可以将派生类型转换为基类型。我刚刚意识到这给我留下的问题是工厂如何正确地处理多级继承。例如,如果 TType 是 BaseCommon,那么它将生成 CaseABase 或 CaseBBase 对象,但如果它是 DerivedCommon(派生自 BaseCommon),那么它将生成 CaseADerivedCommon 或 CaseBDerivedCommon。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多