Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

161
Vistas
Cambiar la firma del delegado en la biblioteca para omitir un argumento no interrumpe las aplicaciones que lo usan

Considere el siguiente código en una biblioteca de clases:

 public class Service { public delegate string Formatter(string s1, string s2); public void Print(Formatter f) { Console.WriteLine(f("a", "b")); } }

Y aquí hay una aplicación de consola que lo usa:

 static void Main(string[] args) { s = new Service(); s.Print(Concat); } static string Concat(string s1, string s2) { return string.Format("{0}-{1}", s1, s2); }

Hasta ahora imprime " ab ", tal como cabría esperar.

Ahora, cambio la biblioteca de clases de la siguiente manera:

 public class Service { public delegate string Formatter(string s1); public void Print(Formatter f) { Console.WriteLine(f("a")); } }

Es decir, eliminé un parámetro del delegado. Compilo solo la biblioteca de clases y sobrescribo el dll que se encuentra junto a la aplicación de la consola (la aplicación de la consola no se vuelve a compilar). Espero que este sea un cambio importante en la biblioteca y si ejecuto la aplicación, encuentra la falta de coincidencia, lo que resulta en alguna excepción de tiempo de ejecución.

Por el contrario, cuando ejecuto la aplicación no hay ninguna excepción y obtengo el sorprendente resultado " -a ". Cuando depuro, puedo ver que se llama al método Concat (con 2 parámetros), el nivel de la pila de llamadas a continuación muestra la llamada de impresión a f ("a") (un parámetro), sin indicación de error en ninguna parte. Lo más interesante es que en Concat s1 es nulo, s2 es "a".

También jugué con diferentes cambios en la firma (agregando parámetros, cambiando el tipo de parámetro) en su mayoría con el mismo resultado. Cuando cambié el tipo de s2 de string a int, obtuve una excepción, pero no cuando se llamó al método Concat, sino cuando intentó llamar a string.Format.

Lo probé con .NET target framework 4.5.1 y 3.5, x86 y x64.

¿Alguien puede responder si este es el comportamiento esperado o un error? Me parece bastante peligroso.

over 4 years ago · Santiago Trujillo
1 Respuestas
Responde la pregunta

0

Aquí hay una reproducción más simple: básicamente, estoy usando el constructor "bajo el capó" en el tipo de delegado (el que usa IL) para pasar un objetivo de método con la firma incorrecta, y ... funciona bien (por lo cual Quiero decir que no arroja una excepción, se comporta como su código):

 using System; static class P { static void Main() { // resolve the (object, IntPtr) ctor var ctor = typeof(Func<string, string>).GetConstructors()[0]; // resolve the target method var mHandle = typeof(P).GetMethod(nameof(Concat)) .MethodHandle.GetFunctionPointer(); object target = null; // because: static // create delegate instance var del = (Func<string, string>)ctor.Invoke(new object[] { target, mHandle }); var result = del("abc"); Console.WriteLine(result); // "-abc" } public static string Concat(string s1, string s2) { return string.Format("{0}-{1}", s1, s2); } }

Esto no es realmente una explicación. ¡Pero podría ser útil si desea preguntarle a alguien más experto en CLR! Hubiera esperado que el constructor delegado se quejara en voz alta de que el objetivo era incorrecto.

Como suposición (pura especulación), es un caso de: si está pasando un IntPtr (int nativo), entonces está completamente solo: el código hace lo más rápido posible. ¡Sin embargo, parece una trampa desagradable para los incautos!

En cuanto a por qué s2 tiene el valor y s1 está vacío: supongo que se debe a que la pila se acumula hacia abajo (no hacia arriba), por lo tanto, en un método de dos parámetros, arg1 es el parámetro inmediatamente adyacente a la posición anterior en la pila. Cuando pasamos un solo valor en lugar de dos, solo ponemos un valor debajo, por lo que s2 tiene un valor y s1 no está definido (podría ser basura del código anterior).

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda