creo que esto es lo que está sucediendo bajo el capó de Foo((dynamic)a)
:
Asset a = new House();
Type t = typeof(MainClass);
t.InvokeMember("Foo",
System.Reflection.BindingFlags.InvokeMethod, null,
t, new object[] { a });
que resolverá a Foo(House h)
Un viaje rápido a monodis.exe, sin necesidad de utilizar la reflexión (por ejemplo InvokeMember) , es decir, utilizando la palabra clave dinámica en su lugar, Asset a = new House(); Foo((dynamic)a)
, esta es la IL:
IL_0025: ldstr "Foo"
IL_002a: ldnull
IL_002b: ldtoken MainClass
IL_0030: call class [mscorlib]System.Type class [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
Más o menos lo que es su corazonada le dirá, el "Foo" es un regalo muerto que la dinámica es reflexión-y tipo de negocio.
Ahora bien, esto es sans dinámicos, es decir Asset a = new House(); Foo(a)
:
IL_0010: ldloc.0
IL_0011: call void class MainClass::Foo(class Asset)
La instrucción quemado es más o menos decidido, no va a cambiar, siempre se resuelven a Foo(Asset);
Aquí está el código completo se puede utilizar para analizar el comportamiento dinámico (a través de monodis.exe o ildasm.exe):
using System;
public class MainClass {
public static void Main() {
Console.WriteLine("Hei");
Asset a = new House();
Foo(a);
Foo((dynamic)a);
object x = 7;
Foo((dynamic)x);
}
public static void Foo(House h) { Console.WriteLine("House"); }
public static void Foo(Asset a) { Console.WriteLine("Asset"); }
public static void Foo(int i) { Console.WriteLine("int"); }
}
public class Asset {
}
public class House : Asset {
}
de salida:
Hei
Asset
House
int
Esto invocará el int sobrecarga Foo, es decir Foo(int i)
:
object x = 7;
t.InvokeMember("Foo", System.Reflection.BindingFlags.InvokeMethod, null,
t, new object[] { x });
Esto también lo haría:
t.InvokeMember("Foo", System.Reflection.BindingFlags.InvokeMethod, null,
t, new object[] { 8 });
Así que en su pregunta, ¿qué otra opción que puede utilizar, puede utilizar un método que acepta un objeto sin tipo:
public static void FooDynamic(object o)
{
Type t = typeof(MainClass);
t.InvokeMember("Foo", System.Reflection.BindingFlags.InvokeMethod, null, t, new object[] { o });
}
Invocar:
Asset a = new House();
FooDynamic(a); // will select Foo House overload
int i = 7;
FooDynamic(i); // will select Foo int overload
También puede utilizar esta API para el código anterior: public static void Foo(object o)
, entonces usted tendría que llamar Foo así:
Asset a = new House();
Foo((object)a); // will resolve to House
Teniendo en cuenta que ya hay una capacidad dynamic
en C# 4, estaría en apuros para utilizar la reflexión, a menos que el dev sigue utilizando C# 3. Así que, utilice el enfoque dinámico en lugar :-)
ACTUALIZACIÓN
Por lo vale la pena, dynamic
es lento (al menos en Mono), cuando ejecuto este código, hay un retraso considerable antes de que aparezca la letra "B", unos 2 segundos. La demora de la dinámica es reproducible incluso si cambio el orden de los códigos de dinámica y reflexión. El retraso de la reflexión es imperceptible, es más rápido que dinámico.
using System;
public class MainClass {
public static void Main() {
// there's a delay on initial dynamic call, about two seconds
Test();
Console.ReadLine();
// dynamic's speed is instant on subsequent calls,
// as clarified by Eric Lippert, the delegate is cached,
// hence the elimination of delay on subsequent dynamic calls
Test();
}
public static void Test() {
Asset a = new House();
Console.WriteLine("A");
Foo((dynamic)a); // there is a considerable delay here, the "B" string appears after two seconds
Console.WriteLine ("B");
Type t = typeof(MainClass);
t.InvokeMember("Foo", System.Reflection.BindingFlags.InvokeMethod, null, t, new object[] { a });
Console.WriteLine("C");
}
public static void Foo(House h) { Console.WriteLine("House"); }
public static void Foo(Asset a) { Console.WriteLine("Asset"); }
public static void Foo(int i) { Console.WriteLine("int"); }
}
public class Asset {
}
public class House : Asset {
}
Asset a = new House (...); no llamará a Foo (activo), porque * el tipo de tiempo de ejecución * es House, por lo que llamará a Foo (House) – Tigran
@Tigran: la resolución de sobrecarga se realiza en tiempo de compilación. 'Asset a = nueva Casa (...); Foo (a); 'llamará a' Foo (Asset) 'porque' a' se declara como 'Asset'. – dtb
@dtb: no hay ninguna * sobrecarga * estos son métodos estáticos, y * no * llamará a Foo (activo), e incluso si existe el * significado * de sobrecarga es la identificación del tipo de tiempo de ejecución, y el tipo de tiempo de ejecución en la cadena Asset a = new House() es House. – Tigran