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

时间:2009-09-03 03:49:21

标签: c# generics reflection

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

我有这样的方法:

public static void Method<T>(MethodInfo m, T value)
{
  Type memberType = m.GetValueType();

  if (memberType.IsAssignableFrom(typeof(List<T>))
  {
    object memberValue = Activator.CreateInstance(memberType);
    ((List<T>)memberValue).Add(value);
  }
}

当我这样称呼时,这很好用:

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

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

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

现在,intellisense知道Method&lt; T&gt;中的'value'了。是valueType的任何类型(比如说'FooObject')。但是'T'是对象,这意味着List&lt; FooObject&gt;是可从List&lt; T&gt;分配(即List&lt; object&gt;)。

我之前尝试过对变量('passValue')使用Convert.ChangeType,但这没有任何用处。

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

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

2 个答案:

答案 0 :(得分:5)

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

private static Action<MethodInfo, object> 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<Action<MethodInfo, object>> expr =
        Expression.Lambda<Action<MethodInfo, object>>(
            Expression.Call(method, methodInfo, Expression.Convert(obj, valueType)),
            methodInfo,
            obj);

    return expr.Compile();
}

答案 1 :(得分:4)

你很幸运。几周前我实际上是had to do something very similar

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

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>(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