简体   繁体   English

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

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

No doubt elements of this question have been asked before, but I'm having trouble finding an answer. 毫无疑问,这个问题的元素之前已被问过,但我找不到答案。 (Disclaimer: this is related, but separate from a recent question I asked). (免责声明:这是相关的,但与我最近提出的问题不同)。

I have a method like this: 我有这样的方法:

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);
  }
}

This works fine when I call it like this: 当我这样称它时,这工作正常:

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

However, I need to call this method using a generic type, so I'm calling it like this: 但是,我需要使用泛型类型调用此方法,所以我这样调用它:

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

Now, intellisense knows that 'value' in Method<T> is whatever type valueType is (say 'FooObject'). 现在,intellisense知道Method <T>中的'value'是valueType的任何类型(比如说'FooObject')。 But 'T' is object, which means that a List<FooObject> is not assignable from a List<T> (ie a List<object>). 但是'T'是对象,这意味着List <FooObject> 不能从List <T>(即List <object>)分配。

I've tried using Convert.ChangeType on the variable ('passValue') beforehand but that wasn't any more useful. 我已经尝试事先在变量('passValue')上使用Convert.ChangeType,但这没有任何用处。

As there is no way to cast a variable to the Type of a type variable, how do I get around this? 由于无法将变量强制转换为类型变量的类型,我该如何解决这个问题呢?

Is the best solution to somehow not rely on IsAssignableFrom and do a looser type check of whether this will work? 最好的解决方案是以某种方式不依赖于IsAssignableFrom并做一个更宽松的类型检查这是否有效? The problem with this is that I'm not sure I'll be able to cast the memberValue properly unless 'T' is truly the element type of memberValue. 这个问题是我不确定我是否能够正确地转换memberValue,除非'T'确实是memberValue的元素类型。

This should give you a callable method (I'll test it in a little while). 这应该给你一个可调用的方法(我会在一段时间内测试它)。 The boxing/unboxing it incurs is much faster than the security checks required for the Reflection API invocation (which happens to also require boxing). 它引发的装箱/拆箱比反映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();
}

You're in luck. 你很幸运。 I actually had to do something very similar a few weeks ago. 几周前我实际上不得不做一些非常相似事情

For a detailed explanation see the above blog post, but basically the general idea is to reflect the type and manually invoke the method with an explicit set of parameters. 有关详细说明,请参阅上面的博客文章,但基本上一般的想法是反映类型并使用一组显式参数手动调用该方法。

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

It's not very type safe, but it does exactly what you're looking for. 它不是 非常 类型安全,但它完全符合您的要求。

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 });
    }

}

Output 产量

   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