Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

287
Views
Reflexión: ¿Cómo encuentro e invoco una función local en C# 7.0?

Tengo un método genérico estático privado al que quiero llamar usando la reflexión, pero realmente quiero 'empaquetarlo' 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 tener la capacidad de usar un objeto y System.Type de una manera fuertemente tipada, por lo que necesito 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. Escuché que en tiempo de compilación, el compilador convierte cualquier función local en métodos estáticos, así que bajé a la ventana inmediata y ejecuté:

 application.GetMethods(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)

... Y, de hecho, 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 de la lista. ¿Alguien tiene alguna idea de cómo accedería a un método como ese 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 lugar, así que quería "empaquetarlo" todo dentro de un método.

Además, se suponía que esto era realmente una pregunta sobre cómo encontrar funciones locales en general y no parece haber una pregunta al respecto en ningún otro lugar de StackOverflow. Me cuesta creer que en ALGÚN MOMENTO alguien no sienta, al menos, curiosidad por hacerlo.

En primer lugar, dudaba en proporcionar cualquier código porque solo estoy jugando con una idea, pero el objetivo real que estoy tratando de lograr es secundario a la pregunta en general.

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

Vale, 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 }); } }
over 4 years ago · Santiago Trujillo Report

0

Llamar a una función local con reflejo es como buscar problemas. El nombre no es "fijo". Cambia en función de cuántas otras funciones locales hay en la misma clase... Entonces, si modifica otro método, podría cambiar el nombre de la función local que le interesa.

Puedes echarle un vistazo a este TryRoslyn .

Hay tres clases, Class1 , Class2 y Class3 . Todos tienen un método M que internamente tiene una función local Test . Class1 y Class2 son idénticos al último carácter. Luego, el método local se compila en un método denominado <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 denomina <M>g__Test1_0() .

over 4 years ago · Santiago Trujillo Report

0

Sé que esta es una vieja pregunta ahora, pero estoy tratando de entender por qué exactamente HandleResponse no puede ser un método genérico. Puede pasar el tipo a la función local, que a su vez puede usar el mismo tipo externo. Esto elimina la necesidad de reflexión. Significa que se generarán nuevos métodos con cada llamada usando un tipo diferente, pero no sé cómo podría evitar ese paso en la compilación y ejecución del código, el suyo incluido como UseAs es genérico. Así que esto es lo que estoy pensando.

 using Microsoft.Extensions.DependencyInjection; using Microsoft.VisualStudio.TestTools.UnitTesting; [TestClass] public class testy { class a { } class b : a { } [TestMethod] public void caller() { HandleResponse<a>(new b()); } private static void HandleResponse<T>(object data) { UseAs((T)data); void UseAs(T obj) { System.Diagnostics.Debug.WriteLine($"Object is now a: {typeof(T)}:"); } } }

Supongo que esencialmente está tratando de convertir un tipo en otro tipo válido. Su código no sería de tipo seguro en ese caso, y podría fallar con algo como "obj no se puede convertir para escribir DateTime". Mi solución no es diferente. Supongo que puede convertir su objeto en una T. No estoy comprobando si es convertible a ese tipo (un uso válido de la reflexión en este caso). Así que creo que mi pequeña solución es funcionalmente equivalente.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!