【问题标题】:instantiate a generic class using reflection [duplicate]使用反射实例化一个泛型类
【发布时间】:2013-09-24 18:16:11
【问题描述】:

[注意:我不认为这个问题与上面链接的问题重复,正如我在下面的更新中解释的那样。]

有没有办法使用反射来定义/实例化泛型类?

所以我有一堆类,每个类都拥有一个通用类的实例,该实例共享其所有者的类型:

public class GenericClass<T>
{
    T Owner { get; set; }
    public GenericClass(T owner) { Owner = owner; }
}
public class MyClass
{
    private GenericClass<MyClass> myGenericObject;
    public MyClass() { myGenericObject = new GenericClass<MyClass>(this); }
}

这可行,但当然我必须在 GenericClass 定义中明确指定“MyClass”作为参数。我希望能够做这样的事情:

private GenericClass<typeof(this)> myGenericObject; // Error: invalid token

是否有在编译时根据包含的类动态指定泛型对象的类型?


更新:在阅读了thesequestions 的答案后,我了解到我可以像这样实例化一个局部变量:

var myGenericObject = Activator.CreateInstance(typeof(GenericClass<>).MakeGenericType(this.GetType()));

但是,当然,this 关键字只能在方法内部使用(因此,例如,我可以将这行代码放在MyClass 的构造函数中)。但是我不能使用这种方法来定义一个 instance 变量(即,myGenericObject,在上面的代码中)。有什么方法可以动态指定泛型实例变量吗?

【问题讨论】:

  • 您尝试了吗:Activator.CreateInstance()。它是内置的。
  • 泛型类只能有泛型实例字段。
  • @AlexDenysenko:这就是小费;我来看看 CreateInstance 的通用版本。

标签: c# generics


【解决方案1】:

关于您的更新,您可以将任何Type 传递给MakeGenericType。例如,以下内容也有效:

var myObject = new MyClass();

var myGenericObject = Activator.CreateInstance(typeof(GenericClass<>).MakeGenericType(typeof(MyClass)), myObject);

Console.WriteLine(myGenericObject.GetType());

输出:

ConsoleApplication1.GenericClass`1[ConsoleApplication1.MyClass]

myObject.GetType() 也做同样的事情:

var myGenericObject = Activator.CreateInstance(typeof(GenericClass<>).MakeGenericType(myObject.GetType()), myObject);

【讨论】:

  • 谢谢,但重点是我不想明确指定类型。我希望它在编译时动态指定。
  • “编译时动态”到底是什么意思?你的意思是你只是想在编写程序时从你的语法中去掉 吗?在这种情况下,创建一个静态工厂public static GenericClass { public Create&lt;T&gt;(T owner) { return new GenericClass&lt;T&gt;(owner); } },然后您可以调用GenericClass.Create(myObject),编译器将推断类型。
  • 或者你真的只是想说“我想创建一个 GenericClass,其中类型参数是它的所有者的类型”,在这种情况下你可以写 public static GenericClass { public object Create(object owner) { return Activator.CreateInstance(typeof(GenericClass&lt;&gt;).MakeGenericType(object.GetType()), object); } } 然后你可以写 object myObject = new MyClass(); object gc = GenericClass.Create(object) 和确信gc.GetType() == typeof(GenericClass&lt;MyClass&gt;),即使编译器忘记了关于myObject 的所有内容,除了它是object 的事实。
  • (您说得对,我的“动态/编译时间”评论措辞非常糟糕。抱歉造成混淆。)您的第二条评论确实符合我的要求。你有几个错别字,所以一开始它没有编译,但基本上这就是我正在寻找的解决方案。现在唯一的问题是:通过将gc 声明为Object 而不是GenericClass,我是否会在类型安全方面失败?感谢您的帮助!
【解决方案2】:

不确定这是否是您要寻找的,但可以尝试继承:

public class GenericClass<T>
{
    T Owner { get; set; }

    public GenericClass(T owner) { Owner = owner; }
}

public abstract class MyClassBase<T> where T : MyClassBase<T>
{
    protected GenericClass<T> MyGenericObject { get; private set; }

    protected MyClassBase() { MyGenericObject = new GenericClass<T>((T)this); }
}

public class MyClass1 : MyClassBase<MyClass1>
{
    public MyClass1() { }
}

public class MyClass2 : MyClassBase<MyClass2>
{
    public MyClass2() { }
}

【讨论】:

  • 有趣的方法,但它似乎并没有解决指定Type 参数的需要(在你的情况下,为: MyClassBase&lt;MyClass1&gt;),而我正在寻找一种方法来这样做动态。
【解决方案3】:

为此内置了静态构造:

Activator.CreateInstance()

查看重载。

更新

public Type FakeType { get; private set; }
public T CreateInstance<T>() where T : SomeEntityBase
{
     return (T) Activator.CreateInstance(FakeType);
}

【讨论】:

  • 只想指出,还有一个通用的版本:Activator.CreateInstancemsdn.microsoft.com/de-de/library/0hcyx2kd.aspx
  • 我已经做了 =)) 看看问题的 cmets
  • 我很难理解如何使用 CreateInstance 的通用版本,因为 documentation 中的示例代码实际上并未使用该构造。
  • 我更新了答案。是你要找的吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-19
  • 2015-03-06
相关资源
最近更新 更多