Я думаю, что это то, что под капотом Foo((dynamic)a)
происходит:
Asset a = new House();
Type t = typeof(MainClass);
t.InvokeMember("Foo",
System.Reflection.BindingFlags.InvokeMethod, null,
t, new object[] { a });
Это будет решать Foo(House h)
Быстрая поездка в monodis.exe, без использования отражения (например, InvokeMember) , т.е. используя вместо этого динамическое ключевое слово, Asset a = new House(); Foo((dynamic)a)
, это 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)
Довольно многое, что вам догадывается, скажет вам, что «Foo» - это мертвая распродажа, что динамика reflection-y вид бизнеса.
Теперь это без динамика, т.е. Asset a = new House(); Foo(a)
:
IL_0010: ldloc.0
IL_0011: call void class MainClass::Foo(class Asset)
Обожженной инструкция в значительной степени решил, не изменится, она всегда постановляет Foo(Asset);
Вот полный код, который вы можете использовать для анализировать динамическое поведение (через monodis.exe или ildasm.ехе):
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 {
}
Выход:
Hei
Asset
House
int
Это будет вызывать перегрузки Int Foo, т.е. Foo(int i)
:
object x = 7;
t.InvokeMember("Foo", System.Reflection.BindingFlags.InvokeMethod, null,
t, new object[] { x });
Это бы тоже:
t.InvokeMember("Foo", System.Reflection.BindingFlags.InvokeMethod, null,
t, new object[] { 8 });
Так что на ваш вопрос, какой другой вариант вы можете использовать, вы можете использовать метод, который принимает нетипизированный объект:
public static void FooDynamic(object o)
{
Type t = typeof(MainClass);
t.InvokeMember("Foo", System.Reflection.BindingFlags.InvokeMethod, null, t, new object[] { o });
}
Для вызова:
Asset a = new House();
FooDynamic(a); // will select Foo House overload
int i = 7;
FooDynamic(i); // will select Foo int overload
Вы также можете использовать этот API для код выше: public static void Foo(object o)
, то вам придется позвонить Foo, как это:
Asset a = new House();
Foo((object)a); // will resolve to House
Учитывая, что уже есть возможность dynamic
в C# 4, я бы с трудом решился использовать отражение, если Дев не все еще использует C# 3. Так что, использовать динамический подход вместо :-)
UPDATE
за то, что это стоит, dynamic
slow (по крайней мере, на моно), когда я запускаю этот код, перед появлением буквы «B» появляется около 2 секунд. Задержка динамика воспроизводима, даже я меняю порядок кода динамического и отражения. Задержка отражения незаметна, она быстрее динамической.
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 (...); не будет вызывать Foo (Asset), вызывать * runtime * type is House, поэтому он вызывается Foo (House) – Tigran
@Tigran: Разрешение перегрузки выполняется во время компиляции. 'Asset a = новый дом (...); Foo (a); 'будет вызывать' Foo (Asset) ', потому что' a' объявляется как 'Asset'. – dtb
@dtb: нет никакой перегрузки * это статические методы, и это будет * не * вызывать Foo (Asset), и даже если есть * значение * перегрузки, это идентификация типа времени выполнения и тип выполнения в строке Asset a = new House() - это дом. – Tigran