【问题标题】:Creating instance of a generic type from a instance of the type parameter从类型参数的实例创建泛型类型的实例
【发布时间】:2013-05-02 20:42:47
【问题描述】:

我有一个由通用存储库和一些实体类型的特定实现组成的 BL(我的 DAL 是 Entity Framework 5 模型)。存储库几乎使用 System.Data.Entity.DbContext 的方法 Set() 来实现其所有功能。我有一些表达式用于获取实体 T 的兄弟姐妹,这些表达式不适用于 Set(Type entityType) 的结果。

在某一时刻,我有一个非泛型 DbEntityEntry 的实例。实体的类型为 Object。当我使用 GetType() 时,我得到了适当的实体类型。我知道想使用我在存储库中的函数获取相关实体。有没有办法从非泛型 DbEntityEntry 做到这一点。

我试过了:

public Repository(T entity)
{
    \\ Construction here
}

但是我得到了一个Repository<Object> 并且对Set<Object> 的调用没有按预期返回任何结果。

我已经寻找了一种方法来做到这一点,但没有找到。

【问题讨论】:

    标签: c# generics


    【解决方案1】:

    看看 George Mauer 在this 线程中发布的这个例子。它需要 .Net 4.0 或更高版本。

    dynamic DynamicCast(object entity, Type to)
    {
        var openCast = this.GetType().GetMethod("Cast", BindingFlags.Static | BindingFlags.NonPublic);
        var closeCast = openCast.MakeGenericMethod(to);
        return closeCast.Invoke(entity, new[] { entity });
    }
    static T Cast<T>(object entity) where T : object
    {
        return entity as T;
    }
    

    您可以使用对其稍作修改的变体来创建匹配的Repository 实例:

    public static dynamic CreateRepository(object entiry, Type targetType)
    {
        Type BaseType = typeof(Repository<>);   
        Type ConcreteType = BaseType.MakeGenericType(targetType);
        var Instance = Activator.CreateInstance(ConcreteType, entiry);
    
        return DynamicCast(Instance, ConcreteType);
    }
    

    【讨论】:

    • 添加了“CreateRepository”的示例实现
    • 我真的看不出DynamicCast 方法的含义。为什么不把上面CreateRepository方法的最后一行代码改成简单的return Instance;呢?
    • 因为 Activator.CreateInstance 有一个返回类型Object。通过使用 DynamicCast,您可以获得正确的类型。
    • 我提出以下简化:public static object CreateRepository(object entity) { var typeDef = typeof(Repository&lt;&gt;); var constrType = typeDef.MakeGenericType(entity.GetType()); var instance = Activator.CreateInstance(constrType, entity); return instance; }
    • (对您的最新评论):但是您可以根据需要使用从任何类型到类型dynamic 的隐式转换,如dynamic retVal = new object();
    【解决方案2】:

    泛型类型的构造函数是为其泛型类型参数生成的特定类的一部分。例如,List&lt;int&gt; 的构造函数与List&lt;string&gt; 的构造函数不同。换句话说,“找到”该类型的代码不能存在于泛型类中。

    据我所知,这是您的两个选择:

    • 将对象转换为其实际类型(类似工厂的解决方案)
    • 使用反射创建泛型类实例

    要使用反射创建实例,可以使用:

    Type genericType = typeof(List<>);
    Type genericArgument = typeof(int);
    Type specificType = genericType.MakeGenericType(genericArgument);
    object instance = Activator.CreateInstance(specificType); // this is a List<int>
    

    【讨论】:

      【解决方案3】:

      如果你可以约束你的泛型类型有一个无参数的构造函数,这个问题可以很好地解决

      public Repository(T entity) where T : new()
      {
          T foo = new T(); //that's it
      }
      

      【讨论】:

        【解决方案4】:

        你可以这样做:

        T entity = default(T);
        

        这适用于 T 的值类型以及结构和类。其中 T 是一个类,但它确实需要一个无参数的构造函数。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-11-18
          • 1970-01-01
          • 2010-09-09
          • 2014-05-31
          相关资源
          最近更新 更多