2009-09-03 6 views
8

Несомненно, элементы этого вопроса были заданы раньше, но у меня возникли проблемы с поиском ответа. (Отказ от ответственности: это связано, но отдельно от недавнего вопроса, который я задал).Получить фактический тип параметра общего объекта

У меня есть метод, как это:

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 знает, что 'значение' в методе < T> я s любой тип valueType (например, «FooObject»). Но «T» - это объект, что означает, что список < FooObject> равен не, назначаемый из списка < T> (т. Е. Список < объект>).

Я попытался использовать Convert.ChangeType для переменной ('passValue') заранее, но это было не более полезно.

Как нет способа передать переменную переменной типа Type, как мне обойти это?

Лучшее решение, чтобы как-то не полагаться на IsAssignableFrom и сделать более простую проверку типа, будет ли это работать? Проблема заключается в том, что я не уверен, что смогу правильно применить элемент value, если только T не является типом элемента memberValue.

+0

'GetValueType()' - это метод расширения в вашем коде. Но даже не видя его кода, кажется, что метод 'Method ' не делает ... ничего? Я бы хотел дать вам улучшенное решение, но я действительно не могу понять, что вы пытаетесь сделать здесь. –

+0

Да, извините, что getvaluetype - это всего лишь метод вызова FieldType/PropertyType для данного MemberInfo в зависимости от конкретного типа MemberType. Метод добавляет объект к MemberInfo, который представляет список (то есть .a поле или свойство, которое является списком) –

ответ

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 
+0

Ты мой герой :-) –

+0

Это заняло у меня больше времени, чем я хотел бы признать, и я рад, что смог сэкономить время!Happy Coding :) –

5

Это должно дать вам вызываемый метод (я проверить его на некоторое время). Бокс/unboxing он несет много быстрее, чем проверки безопасности, необходимые для вызова API Reflection (что также требует бокса).

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(); 
} 
+0

Похоже, это тоже должно работать :-) Спасибо! Похоже, что он вызывает динамический динамический метод генерации для правильного ввода типа. –

+0

Можете ли вы это продемонстрировать? Я немного не уверен, как это нужно назвать. –

+0

Хорошо, как вы вызываете метод динамически, а не непосредственно, чтобы тип сам разрешал. Я просто подумал, что это что-то похожее. –

 Смежные вопросы

  • Нет связанных вопросов^_^