.NET泛型:使用Activator创建的类型作为泛型显示错误类型?需要解决方法 [英] .NET Generics: Using an Activator created type as a generic shows wrong Type? Need workaround
问题描述
今天真的让我很难过。我确信它很简单,但是......这里是我的示例代码:
using System;
尤其如下:
使用System.Collections;
namespace ConsoleApplication1
{
class Program
{
public ArrayList SomeProp {get;组; }
static void Main(string [] args)
{
//通过反射获取属性的类型。
键入myPropType = typeof(Program).GetProperty(SomeProp)。PropertyType;
//创建一个确定类型的实例。
var x = Activator.CreateInstance(myPropType);
//现在尝试使用该实例,传递给一个通用的方法。
WhatAmI(x);
Console.ReadKey();
$ b private static void WhatAmI< T>(T x)
{
Console.WriteLine(T is:+ typeof(T).FullName) ;
Console.WriteLine(x is:+ x.GetType()。FullName);
code
$ b这里的输出是: / p>
T是:System.Object
x是:System.Collections.ArrayList
基本上这里发生的是我在某个类上有一些属性。它来自哪里/哪里并不重要。重要的部分是我得到该属性的PropertyInfo。从那里开始,我创建了一个类型为Activator的新实例。
现在,如果我将创建的实例传递给一个带泛型参数的函数,作为Object,因为Activator.CreateInstance()返回一个Object,所以var x是一个Object,在这种情况下不是一个ArrayList。
我需要我知道有一个Activator.CreateInstance(),我可以用它来代替,但是我们可以使用Activator.CreateInstance()方法,但我不能在该方法的尖括号内使用Type(PropertyInfo.PropertyType)。
我也可以投射返回的对象,如:
myPropType x =(myPropType)Activator.CreateInstance(myPropType);
但显然这不会编译...加上它无效,因为演员是编译时,我不知道类型,直到运行时,但在概念上它是我需要的... ...
因此我坚持这种类型,但我无法弄清楚如何将它传递给WhatAmI()方法,并且让T为ArrayList,而不是Object。
想法?
$ b在运行时使用类型
调用泛型方法时,需要使用反射 - 和 code> MakeGenericMethod
typeof(Program).GetMethod WhatAmI,
BindingFlags.Static | BindingFlags.NonPublic)
.MakeGenericMethod(x.GetType())。Invoke(null,new object [] {x});
否则,编译器推断
< T>
从变量类型 -object
在这种情况下。
这里的一个要点是可以改进通过只做反射一次 - 即不要使用
Activator
,而是使用通用约束:
pre $ private $ static void WhatAmI< T>()其中T:new()
{
T x = new T();
Console.WriteLine(T is:+ typeof(T).FullName);
Console.WriteLine(x is:+ x.GetType()。FullName);
定义不带 arg的方法一个默认的构造函数;然后:
// //通过反射获取属性的类型。
键入myPropType = typeof(Program).GetProperty(SomeProp)。PropertyType;
//现在调用一个只使用类型
的泛型方法typeof(Program).GetMethod(WhatAmI,
BindingFlags.Static | BindingFlags.NonPublic)
.MakeGenericMethod(myPropType).Invoke(null,null);
仅使用该类型调用方法 - 实例在内创建方法。这通常比反复反射快。
This really has my stumped today. I'm sure its simple, but... Here is my sample code:
using System;
using System.Collections;
namespace ConsoleApplication1
{
class Program
{
public ArrayList SomeProp { get; set; }
static void Main(string[] args)
{
// Get the Type of a property by reflection.
Type myPropType = typeof(Program).GetProperty("SomeProp").PropertyType;
// Create an instance of the determined Type.
var x = Activator.CreateInstance(myPropType);
// Now try to use that instance, passing to a method that takes a generic.
WhatAmI(x);
Console.ReadKey();
}
private static void WhatAmI<T>(T x)
{
Console.WriteLine("T is: " + typeof(T).FullName);
Console.WriteLine("x is: " + x.GetType().FullName);
}
}
}
The output here is:
T is: System.Object
x is: System.Collections.ArrayList
Basically what is going on here is I have some property on some class. It doesnt really matter what/where that comes from. The important part is that I get the PropertyInfo for that property. From there I create a new instance of its Type with Activator.
Now If I pass that created instance to a function that takes a generic parameter, the generic Type always comes across as Object, because Activator.CreateInstance() returns an Object, so "var x" is an Object, not, in this case, an ArrayList.
What I need to happen is for the generic type to be the actual type, int his case "ArrayList".
I know there is an Activator.CreateInstance() that I can use instead, but I can't use a Type (PropertyInfo.PropertyType) within the angle brackets for that method.
I could also just cast the returned object, like:
myPropType x = (myPropType)Activator.CreateInstance(myPropType);
But obviously that doesn't compile... Plus it wouldn't be valid anyway because the cast is compile time, and I don't know the type until runtime, but conceptually its what I need...
So I'm stuck with this Type, but I can't figure out how to get it passed over to the WhatAmI() method, and have T be ArrayList, not Object.
Ideas?
To call generic methods using a Type
at runtime, you need to use reflection - and MakeGenericMethod
in particular, something like:
typeof(Program).GetMethod("WhatAmI",
BindingFlags.Static | BindingFlags.NonPublic)
.MakeGenericMethod(x.GetType()).Invoke(null, new object[] { x });
Otherwise, the compiler infers the <T>
from the variable type - object
in this case.
One side point here is that you can improve things by only doing the reflection once - i.e. don't use Activator
, but use a generic constraint instead:
private static void WhatAmI<T>() where T : new()
{
T x = new T();
Console.WriteLine("T is: " + typeof(T).FullName);
Console.WriteLine("x is: " + x.GetType().FullName);
}
Defines the method without an arg, but with a default constructor; then:
// Get the Type of a property by reflection.
Type myPropType = typeof(Program).GetProperty("SomeProp").PropertyType;
// Now call a generic method just using the type
typeof(Program).GetMethod("WhatAmI",
BindingFlags.Static | BindingFlags.NonPublic)
.MakeGenericMethod(myPropType).Invoke(null, null);
calls the method just using the type - the instance is created inside the method. This is usually faster than repeated reflection.
这篇关于.NET泛型:使用Activator创建的类型作为泛型显示错误类型?需要解决方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!