Configuración de tipo genérico en tiempo de ejecución

Tengo una clase

public class A { public static string B(T obj) { return TransformThisObjectToAString(obj); } } 

El uso de la secuencia anterior es puramente ejemplar. Puedo llamar a la función estática así simplemente en un tipo conocido / especificado:

 string s= A.B(objectOfKnownType); 

¿Cómo hago esta llamada? Si no sé T de antemano, prefiero tener una variable del tipo Tipo que contenga el tipo. Si hago esto:

 Type t= typeof(string); string s= A.B(someStringObject); 

Me sale este error del comstackdor:

 Cannot implicitly convert type 't' to 'object' 

No puedes. Los identificadores generics de tipos deben conocerse en tiempo de comstackción.

editar

a partir de otras publicaciones, parece ser posible generando dinámicamente el método e invocándolo, lo que tiene sus riesgos, por supuesto. Vea las publicaciones de Thomas y Dathan para obtener más información.

No puede hacer esto directamente, pero puede usar reflection para proporcionar un parámetro de tipo de una clase en tiempo de ejecución. No lo he probado, pero algo así debería funcionar:

 // We want to do something like this: // object o = "Hello" // Type t = o.GetType(); // // This is pseudo-code only: // string s = A.B(o); string InvokeA(object o) { // Specify the type parameter of the A<> type Type genericType = typeof(A<>).MakeGenericType(new Type[] { o.GetType() }); // Get the 'B' method and invoke it: object res = genericType.GetMethod("B").Invoke(new object[] { o }); // Convert the result to string & return it return (string)res; } 

Por supuesto, la pregunta es si esto es realmente lo que necesita: si no sabe nada sobre el objeto dado como argumento, también podría escribir todo el código simplemente usando el objeto. Sin embargo, puedo imaginar algunos escenarios donde esto sería útil, así que supongo que puedes intentar usar esto.

Hay absolutamente apoyo para esto en el marco y el CLR, simplemente no con gracia en C #. Sin embargo, puedes lograr lo que yo creo que quieres con la ayuda de un método de ayuda:

 public class A { public static string B(T obj) { return obj.ToString(); } } public class MyClass { public static void DoExample() { Console.WriteLine(ExecuteB("Hi")); Console.WriteLine(ExecuteB(DateTime.Now)); } public static object ExecuteB(object arg) { Type arg_type = arg.GetType(); Type class_type = typeof(MyClass); MethodInfo mi = class_type.GetMethod("ExecuteBGeneric", BindingFlags.Static | BindingFlags.Public); MethodInfo mi2 = mi.MakeGenericMethod(new Type[] { arg_type }); return mi2.Invoke(null, new object[] { arg }); } public static object ExecuteBGeneric(T arg) { return A.B(arg); } 

No puedes. Pero has hecho la pregunta incorrecta para el caso provisto. En este caso (como en el 99% de los casos), todo lo que realmente necesita es una restricción de tipo .

Tratar:

 public class A where T : object 

o, si T es una clase conocida, una subclase o una interfaz, entonces sería mejor usar

 public class A where T : YourAbstractClass 

También existen otras restricciones de tipo. Más detalles: http://msdn.microsoft.com/en-us/library/d5x73970(VS.80).aspx

Como nota general, cuando aprendes un nuevo idioma, a menudo tienes que pensar ampliamente sobre lo que quieres lograr , no específicamente encontrar lo que quieres hacer . Esto es muy parecido a los lenguajes verbales del mundo real. Es la diferencia entre aprender alemán leyendo un diccionario y forzando las palabras a la syntax en inglés, o aprendiendo la syntax y recogiendo las palabras. Sí, un hablante alemán entenderá a alguien que está hablando fuera del diccionario, pero la WTF por recuento de oraciones será mucho más alta.

Intentar sustituir el parámetro de tipo en el tiempo de ejecución frustrará el propósito del tipo de seguridad, que se impone mediante el comstackdor de C #. El comstackdor # C hace que ese tipo de parámetro se especifique en tiempo de comstackción y no haya ambigüedad en los argumentos de tipo en tiempo de ejecución. Dudo que pueda sustituye el parámetro de tipo en tiempo de ejecución en Tipo genérico. Especificar el argumento de tipo de tipo ” Tipo ” es casi como tener un tipo genérico no vinculado.

Creé este método de ayuda basado en algunas de las respuestas aquí y en otras partes de la web.

uso:

 InvokeGenericMethodWithRuntimeGenericArguments( MyMethodWithGenericType, new[] {MyRuntimeGenericType}, null); 

método:

 public static object InvokeGenericMethodWithRuntimeGenericArguments(Action methodDelegate, Type[] runtimeGenericArguments, params object[] parameters) { if (parameters == null) { parameters = new object[0]; } if (runtimeGenericArguments == null) { runtimeGenericArguments = new Type[0]; } var myMethod = methodDelegate.Target.GetType() .GetMethods() .Where(m => m.Name == methodDelegate.Method.Name) .Select(m => new { Method = m, Params = m.GetParameters(), Args = m.GetGenericArguments() }) .Where(x => x.Params.Length == parameters.Length && x.Args.Length == runtimeGenericArguments.Length ) .Select(x => x.Method) .First().MakeGenericMethod(runtimeGenericArguments); return myMethod.Invoke(methodDelegate.Target, parameters); }