繁体   English   中英

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

[英]Get the actual type of a generic object parameter

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

我有这样的方法:

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 <T>中的'value'是valueType的任何类型(比如说'FooObject')。 但是'T'是对象,这意味着List <FooObject> 不能从List <T>(即List <object>)分配。

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

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

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

这应该给你一个可调用的方法(我会在一段时间内测试它)。 它引发的装箱/拆箱比反映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();
}

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

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

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

暂无
暂无

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

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