Reflexión: ¿Cómo encuentro e invoco una función local en C#7.0?
methods reflection (2)
De acuerdo, tengo una solución. Pero es realmente horrible . Implica crear un delegado de su método con un tipo específico , luego usarlo para encontrar el método genérico , luego construir otro método específico e invocarlo.
Así que pasamos de UseAs<int>
a UseAs<T>
a UseAs<the-type-we-want>
.
Podría salir terriblemente mal de muchas maneras, pero funciona para la muestra muy limitada que he probado:
// DISCLAIMER: THIS CODE IS FAIRLY HACKY, AND MAY WELL FAIL IN WEIRD
// SITUATIONS. USE WITH EXTREME CAUTION AND LOTS OF TESTS!
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main(string[] args)
{
HandleResponse("foo", typeof(string));
}
static void HandleResponse(object data, Type type)
{
string local = "This was a local variable";
void UseAs<T>(T obj)
{
Console.WriteLine($"Object is now a: {typeof(T)}:");
// Proof that we''re capturing the target too
Console.WriteLine($"Local was {local}");
}
InvokeHelper(UseAs, data, type);
}
// This could be in any class you want
static void InvokeHelper(Action<int> int32Action, object data, Type type)
{
// You probably want to validate that it really is a generic method...
var method = int32Action.Method;
var genericMethod = method.GetGenericMethodDefinition();
var concreteMethod = genericMethod.MakeGenericMethod(new[] { type });
concreteMethod.Invoke(int32Action.Target, new[] { data });
}
}
Tengo un método genérico estático privado al que quiero llamar utilizando la reflexión, pero realmente quiero ''agruparlo'' dentro de otro método. C # 7.0 admite funciones locales, por lo que definitivamente es posible.
Dirías "¿por qué no lo llamas directamente?" pero lo estoy usando para obtener la capacidad de usar un objeto y System.Type de una manera fuertemente tipada, así que debo llamarlo dinámicamente. Este código ya funciona si lo tengo como su propio método genérico estático privado.
private static void HandleResponse(object data, Type asType)
{
var application = typeof(Program);
application
.GetMethod(nameof(UseAs), BindingFlags.Static | BindingFlags.NonPublic)
.MakeGenericMethod(asType)
.Invoke(null, new object[] { data });
}
public static void UseAs<T>(T obj)
{
Console.WriteLine($"Object is now a: {typeof(T)}:");
};
El código anterior funciona. Si paso:
data: new TestObject(),
type: typeof(TestObject)
De hecho, tendré un TestObject dentro de UseAs.
Entonces, quería poner todo esto en un solo método, así:
private static void HandleResponse(object data, Type asType)
{
void useAs<T>(T obj)
{
Console.WriteLine($"Object is now a: {typeof(T)}:");
};
var application = typeof(Program);
application
.GetMethod(nameof(UseAs), BindingFlags.Static | BindingFlags.NonPublic)
.MakeGenericMethod(asType)
.Invoke(null, new object[] { data });
}
Desafortunadamente, el código GetMethod ya no funciona. Había escuchado que en tiempo de compilación el compilador convertía cualquier función local a métodos estáticos, así que aparecí en la ventana inmediata y ejecuté:
application.GetMethods(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)
... Y, realmente SÍ veo esta respuesta:
{System.Reflection.MethodInfo[3]}
[0]: {Void Main(System.String[])}
[1]: {Void HandleResponse(System.Object, System.Type)}
[2]: {Void <HandleResponse>g__useAs1_0[T](T)}
Es el último método en la lista. ¿Alguien tiene alguna idea de cómo accedería a un método así de una manera razonable?
¡Gracias!
editar:
De hecho, puedo usar UseAs como un método estático privado ordinario. Simplemente no se va a usar en ningún otro lado, así que quería "empaquetarlo" dentro de un solo método.
Además, se suponía que esto realmente era una pregunta sobre la búsqueda de funciones locales en general y no parece haber dudas al respecto en StackOverflow. Encuentro difícil de creer que, ALGUNOS PUNTOS, al menos alguien tenga curiosidad de hacerlo.
En un principio, dudaba en proporcionar ningún código porque estoy retocando con una idea, pero el objetivo real que estoy tratando de lograr es secundario a la pregunta en conjunto.
Llamar a una función local con reflexión es como buscar problemas. El nombre no es "fijo". Cambia en función de cuántas otras funciones locales hay en la misma clase ... Por lo tanto, si modifica otro método, podría cambiar el nombre de la función local que le interese.
Puedes echarle un vistazo a este TryRoslyn .
Hay tres clases, Class1
, Class2
y Class3
. Todos ellos tienen un método M
que internamente tiene una función local Test
. Class1
y Class2
son idénticos al último personaje. El método local luego se compila a un método llamado <M>g__Test0_0()
. Class3
introduce antes del método M
otro método, Filler
, con otra función local ( Foo
) que luego se compila en <Filler>g__Foo0_0
. En este caso, el método local de M
se llama <M>g__Test1_0()
.