获取通用对象参数的实际类型

毫无疑问,这个问题的元素之前已被问过,但我找不到答案。 (免责声明:这是相关的,但与我最近提出的问题不同)。

我有这样的方法:

public static void Method(MethodInfo m, T value) { Type memberType = m.GetValueType(); if (memberType.IsAssignableFrom(typeof(List)) { object memberValue = Activator.CreateInstance(memberType); ((List)memberValue).Add(value); } } 

当我这样称它时,这工作正常:

 string s = "blah"; Method(memberInfo, s); 

但是,我需要使用generics类型调用此方法,所以我这样调用它:

 Type valueType = someType; object passValue = someMethod.MakeGenericMethod(new Type[] { valueType }).Invoke(this, new object[] { }); /* Call my original method */ Method(memberInfo, passValue ); 

现在,intellisense知道Method 中的’value’是valueType的任何类型(比如说’FooObject’)。 但是’T’是对象,这意味着List 不能从List (即List )分配。

我已经尝试事先在变量(’passValue’)上使用Convert.ChangeType,但这没有任何用处。

由于无法将变量强制转换为类型变量的类型,我该如何解决这个问题呢?

最好的解决方案是以某种方式不依赖于IsAssignableFrom并做一个更宽松的类型检查这是否有效? 这个问题是我不确定我是否能够正确地转换memberValue,除非’T’确实是memberValue的元素类型。

你很幸运 几周前我实际上必须做一些非常相似的事情 。

有关详细说明,请参阅上面的博客文章,但基本上一般的想法是反映类型并使用一组显式参数手动调用该方法。

 typeof(MyClass).GetMethod("Foo").MakeGenericMethod(new[] { param.GetType() }).Invoke(null, new[] { param }); 

它不是非常类型安全,但它完全符合您的要求。

 class Program { static void Main(string[] args) { object str = "Hello World"; object num = 5; object obj = new object(); Console.WriteLine("var\tvalue\t\tFoo() Type\tCallFoo() Type"); Console.WriteLine("-------------------------------------------------------"); Console.WriteLine("{0}\t{1}\t{2}\t{3}", "str", str, MyClass.Foo(str), MyClass.CallFoo(str)); Console.WriteLine("{0}\t{1}\t\t{2}\t{3}", "num", num, MyClass.Foo(num), MyClass.CallFoo(num)); Console.WriteLine("{0}\t{1}\t{2}\t{3}", "obj", obj, MyClass.Foo(obj), MyClass.CallFoo(obj)); } } class MyClass { public static Type Foo(T param) { return typeof(T); } public static Type CallFoo(object param) { return (Type)typeof(MyClass).GetMethod("Foo").MakeGenericMethod(new[] { param.GetType() }).Invoke(null, new[] { param }); } } 

产量

  var value Foo() Type CallFoo() Type ------------------------------------------------------- str Hello World System.Object System.String num 5 System.Object System.Int32 obj System.Object System.Object System.Object 

这应该给你一个可调用的方法(我会在一段时间内测试它)。 它引发的装箱/拆箱比reflectionAPI调用所需的安全检查快得多(这也需要装箱)。

 private static Action BuildAccessor(Type valueType) { MethodInfo genericMethod = null; // <-- fill this in MethodInfo method = genericMethod.MakeGenericMethod(new Type[] { valueType }); ParameterExpression methodInfo = Expression.Parameter(typeof(MethodInfo), "methodInfo"); ParameterExpression obj = Expression.Parameter(typeof(object), "obj"); Expression> expr = Expression.Lambda>( Expression.Call(method, methodInfo, Expression.Convert(obj, valueType)), methodInfo, obj); return expr.Compile(); }