2009-09-03 39 views
8

Sin duda, ya se han formulado elementos de esta pregunta, pero me cuesta encontrar una respuesta. (Descargo de responsabilidad: esto está relacionado, pero separado de una pregunta reciente que hice).Obtiene el tipo real de un parámetro de objeto genérico

Tengo un método como este:

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

Esto funciona bien cuando llamo así:

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

Sin embargo, tengo que llamar a este método utilizando un tipo genérico, por lo que Llamo así:

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

Ahora, intelisense sabe que el 'valor' en el Método < T> i s cualquier tipo valueType es (digamos 'FooObject'). Pero 'T' es un objeto, lo que significa que una Lista < FooObject> es no asignable de una Lista < T> (es decir, un objeto List <>).

He intentado utilizar Convert.ChangeType en la variable ('passValue') de antemano, pero eso ya no era útil.

Como no hay forma de convertir una variable al tipo de una variable de tipo, ¿cómo puedo evitar esto?

¿Es la mejor solución no confiar en IsAssignableFrom y hacer una comprobación más flexible de si esto funcionará? El problema con esto es que no estoy seguro de poder lanzar MemberValue correctamente a menos que 'T' sea realmente el tipo de elemento de memberValue.

+0

'GetValueType()' es un método de extensión en su código. Pero incluso sin ver su código, parece que el método 'Método ' no funciona ... ¿nada? Me gustaría ofrecerte una solución mejorada, pero realmente no puedo entender qué estás tratando de hacer aquí. –

+0

Sí, lo siento getvaluetype es solo un método para llamar a FieldType/PropertyType para un MemberInfo dado, dependiendo del MemberType en particular. El método agrega un objeto a un MemberInfo que representa una lista (es decir, un campo o propiedad que es una lista) –

Respuesta

4

Estás de enhorabuena. De hecho, had to do something very similar hace unas semanas.

Para una explicación detallada, consulte la publicación de blog anterior, pero básicamente la idea general es reflejar el tipo e invocar manualmente el método con un conjunto explícito de parámetros.

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

No es muy tipo de seguro, pero hace exactamente lo que estás buscando.

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

} 

salida

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

Eres mi héroe :-) –

+0

Eso me llevó más tiempo del que me importa admitir y me alegro de poder ahorrarte el tiempo!Happy Coding :) –

5

Esto debería darle un método exigible (Voy a probar que dentro de un rato). El boxeo/unboxing en el que incurre es mucho más rápido que las comprobaciones de seguridad requeridas para la invocación de Reflection API (que también requiere el boxeo).

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

Parece que esto debería funcionar también :-) ¡Gracias! Parece que se trata de llamar dinámicamente al método genérico para convertir el tipo en el correcto. –

+0

¿Puedes demostrar esto? No estoy seguro de cómo se debe llamar. –

+0

Bueno, está llamando al método de forma dinámica en lugar de directamente para que el tipo se resuelva solo. Me imaginaba que esto estaba haciendo algo similar. –

Cuestiones relacionadas