简体   繁体   English

从type参数的实例创建通用类型的实例

[英]Creating instance of a generic type from a instance of the type parameter

I have a BL consisting of a generic Repository and some specific implementations for a couple of entity types (My DAL is a Entity Framework 5 model). 我有一个由通用存储库和一些针对几种实体类型的特定实现组成的BL(我的DAL是Entity Framework 5模型)。 The Repository uses for almost all it's functionality the method Set() of the System.Data.Entity.DbContext. 存储库几乎使用System.Data.Entity.DbContext的Set()方法来实现所有功能。 I have some Expressions for things like getting siblings of a entity T, these won't work on the result of Set(Type entityType). 我有一些用于获取实体T的同级对象的表达式,这些表达式不适用于Set(Type entityType)的结果。

At one moment I have a instance of a non-generic DbEntityEntry. 有一瞬间,我有一个非通用DbEntityEntry的实例。 The entity is of type Object. 该实体的类型为Object。 When I use GetType() I get the approptiate Entity Type. 当我使用GetType()时,我得到适当的实体类型。 I know want to get the related entity using my functions in Repository. 我知道要使用存储库中的函数来获取相关实体。 Is there a way to do this from the non-generic DbEntityEntry. 有没有一种方法可以从非泛型DbEntityEntry中做到这一点。

I tried: 我试过了:

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

But I get a Repository<Object> and the call to Set<Object> returns nothing as expected. 但是我得到一个Repository<Object> ,对Set<Object>的调用未返回任何预期的结果。

I've searched for a way to do this but came up empty. 我一直在寻找一种方法来做,但是空了。

The constructor of a generic type is part of the specific class generated for its generic type argument. 泛型类型的构造函数是为其泛型类型参数生成的特定类的一部分。 For instance, the constructor of a List<int> is a different constructor than that of a List<string> . 例如, List<int>的构造函数与List<string>构造函数是不同的 In other words, the code that "finds" the type cannot exist inside the generic class. 换句话说,“查找”类型的代码不能存在于泛型类中。

As far as I know these are your two options: 据我所知,这是您的两个选择:

  • convert the object to its actual type (a factory-like solution) 将对象转换为其实际类型(类似于工厂的解决方案)
  • use reflection to create the generic class instance 使用反射创建泛型类实例

To create an instance using reflection, you can use: 要使用反射创建实例,可以使用:

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

Take a look at this example posted by George Mauer in this thread. 让我们看一下George Mauer在主题中发布的示例。 It requires .Net 4.0 or higher. 它要求.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;
}

You can use a slightly modified variant of this to create a matching Repository instance: 您可以使用对此稍加修改的变体来创建匹配的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);
}

If you can constraint your generic types to have a parameterless constructor, this problem can be solved pretty elegantly 如果可以将泛型类型约束为具有无参数构造函数,则可以很好地解决此问题

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

You can do: 你可以做:

T entity = default(T);

This works for both value types of T, as well as structs and classes. 这适用于T的值类型以及结构和类。 Where T is a class however it does require a parameterless constructor. 但是,在T是一个类的情况下,它确实需要无参数的构造函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM