2009-09-03 19 views
8

Bez wątpienia elementy tego pytania zostały zadane wcześniej, ale mam problem ze znalezieniem odpowiedzi. (Zrzeczenie się: jest to powiązane, ale oddzielne od ostatnio zadawanego pytania).Uzyskaj rzeczywisty typ ogólnego parametru obiektu

Mam metodę tak:

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

Działa to dobrze, gdy nazywam go tak:

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

Jednak muszę wywołać tej metody przy użyciu typu rodzajowego, więc „m nazywając go tak:

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

teraz intellisense wie, że 'wartość' w metodzie < T> i s dowolny typ valueType (powiedzmy "FooObject"). Ale "T" jest obiektem, co oznacza, że ​​Lista można przypisać z Listy < T> (tj. Obiekt z Listy>> <>).

Próbowałem wcześniej użyć Convert.ChangeType na zmiennej ("passValue"), ale to nie było bardziej użyteczne.

Ponieważ nie ma sposobu na wyrzucenie zmiennej do typu zmiennej typu, jak to obejść?

Czy to najlepsze rozwiązanie, aby w jakiś sposób nie polegać na IsAssignableFrom i zrobić luźniejszą kontrolę typu, czy to zadziała? Problem polega na tym, że nie jestem pewien, czy będę w stanie prawidłowo obsłużyć wartość memberValue, chyba że "T" jest rzeczywiście typem elementu memberValue.

+0

'GetValueType()' jest metodą rozszerzenia w kodzie. Ale nawet bez zobaczenia jego kodu, wygląda na to, że metoda "Metoda " nie robi ... nic? Chciałbym dać ci ulepszone rozwiązanie, ale naprawdę nie mogę zrozumieć, co próbujesz tutaj zrobić. –

+0

Tak, przepraszam getvaluetype jest po prostu metodą wywoływania FieldType/PropertyType dla danego MemberInfo w zależności od określonego MemberType. Metoda dołącza obiekt do elementu MemberInfo, który reprezentuje listę (tj. Pole lub właściwość, która jest listą) –

Odpowiedz

4

Masz szczęście. Faktycznie had to do something very similar kilka tygodni temu.

Aby uzyskać szczegółowe wyjaśnienie, zobacz powyższy wpis na blogu, ale zasadniczo ogólną ideą jest odzwierciedlenie typu i ręczne wywołanie metody z jawnym zestawem parametrów.

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

To nie bardzo typ bezpieczne, ale robi dokładnie to, czego szukasz.

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

} 

Wyjście

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

Jesteś moim bohaterem :-) –

+0

Zajęło mi to dłużej, niż się staram przyznać i cieszę się, że mogłem zaoszczędzić czas!Happy Coding :) –

5

To powinno dać metodę wpłacone (będę go przetestować za chwilę). Boksowanie/rozpakowywanie, które powoduje, jest znacznie szybsze niż kontrole bezpieczeństwa wymagane do wywołania interfejsu API Reflection (co również wymaga boksowania).

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

Wygląda na to, że to też powinno działać :-) Dzięki! Wydaje się sprowadzać do dynamicznego wywoływania metody ogólnej w celu rzucenia odpowiedniego typu. –

+0

Czy możesz to zademonstrować? Nie jestem pewien, jak to nazwać. –

+0

Tak jak wywołujecie metodę raczej dynamicznie niż bezpośrednio, aby typ sam się rozwiązał. Po prostu wyobrażałem sobie, że robi to coś podobnego. –

Powiązane problemy