He estado tratando de usar la reflexión para comparar objetos cuyo tipo no se conoce en el momento de la compilación, y en lugar de llamar a Invoke() cada vez que intento usar CreateDelegate(). Lo he hecho funcionar hasta ahora en una clase tipificada genéricamente para primitivos y similares, pero me encontré con una pared de ladrillos con objetos de tipo KeyValuePair<TKey,TValue>. se lanza con
System.ArgumentException: 'No se puede enlazar con el método de destino porque su firma o transparencia de seguridad no es compatible con la del tipo de delegado'.
cuando se llama a CreateDelegate() a pesar de que la firma del método coincide con los tipos proporcionados y devueltos por Invoke(), y no puedo averiguar qué es lo que estoy haciendo mal. El código mínimo para reproducir la excepción es el siguiente:
static void Main(string[] args) { var kvp = new KeyValuePair<string, string>("test key", "test value"); var getKeyMethod = typeof(KeyValuePair<string, string>).GetProperty("Key").GetGetMethod(); Console.WriteLine(getKeyMethod.Invoke(kvp, null)); //works fine var getKey = (Func<KeyValuePair<string, string>, string>) getKeyMethod.CreateDelegate(typeof(Func<KeyValuePair<string, string>, string>)); //exception thrown here Console.WriteLine(getKey(kvp)); //never gets here }Me doy cuenta de que lo mismo es posible usando árboles de expresión, y lo he hecho funcionar usando exactamente la misma firma de método, como se muestra a continuación:
ParameterExpression targetExp = Expression.Parameter(typeof(KeyValuePair<string, string>), "target"); MemberExpression propertyExp = Expression.Property(targetExp, typeof(KeyValuePair<string, string>).GetProperty("Key")); var getKeyMethod = Expression.Lambda<Func<KeyValuePair<string, string>, string>>(propertyExp, targetExp).Compile();De todos modos, me gustaría entender qué es lo que está fallando aquí (los árboles de expresión también son un poco más lentos, pero lo que más me molesta es que no puedo hacer que esto funcione).
KeyValuePair<,> es una estructura. Hay reglas especiales para estructuras y delegados. Para acceder a un método de instancia, básicamente necesita un delegado con un parámetro ref . Por ejemplo, lo siguiente funciona como se esperaba:
// define delegate delegate string RefDel(ref KeyValuePair<string, string> kvp); // in method var kvp = new KeyValuePair<string, string>("test key", "test value"); var getKeyMethod = typeof(KeyValuePair<string, string>).GetProperty("Key").GetGetMethod(); var getKey = (RefDel)getKeyMethod.CreateDelegate(typeof(RefDel)); Console.WriteLine(getKey(ref kvp)); // "test key"Vea aquí un ejemplo en vivo.