I think this is what's happening under the hood of Foo((dynamic)a)
:
Asset a = new House();
Type t = typeof(MainClass);
t.InvokeMember("Foo",
System.Reflection.BindingFlags.InvokeMethod, null,
t, new object[] { a });
That will resolve to Foo(House h)
A quick trip to monodis.exe, without using reflection(e.g. InvokeMember), i.e. using dynamic keyword instead, Asset a = new House(); Foo((dynamic)a)
, this is the 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)
Pretty much what's your hunch shall tell you, the "Foo" is a dead giveaway that dynamic is reflection-y kind of business.
Now, this is sans dynamic, i.e. Asset a = new House(); Foo(a)
:
IL_0010: ldloc.0
IL_0011: call void class MainClass::Foo(class Asset)
The burned instruction is pretty much decided, will not change, it always resolve to Foo(Asset);
Here's the complete code you can use to analyze the dynamic behavior (via monodis.exe or 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 {
}
Output:
Hei
Asset
House
int
This will invoke the Foo overload int, i.e. Foo(int i)
:
object x = 7;
t.InvokeMember("Foo", System.Reflection.BindingFlags.InvokeMethod, null,
t, new object[] { x } );
This would too:
t.InvokeMember("Foo", System.Reflection.BindingFlags.InvokeMethod, null,
t, new object[] { 8 } );
So on your question, what other option you can use, you can use a method that accepts a an untyped object:
public static void FooDynamic(object o)
{
Type t = typeof(MainClass);
t.InvokeMember("Foo", System.Reflection.BindingFlags.InvokeMethod, null, t, new object[] { o } );
}
To invoke:
Asset a = new House();
FooDynamic(a); // will select Foo House overload
int i = 7;
FooDynamic(i); // will select Foo int overload
You can also use this API for the code above: public static void Foo(object o)
, then you would have to call Foo like this:
Asset a = new House();
Foo((object)a); // will resolve to House
Given that there's already a dynamic
capability in C# 4, I would be hard-pressed to use reflection, unless the dev is still using C# 3. So there, use the dynamic approach instead :-)
UPDATE
For what it's worth, dynamic
is slow (at least on Mono), when I run this code, there is a considerable delay before the letter "B" appear, about 2 seconds. The dynamic's delay is reproducible even I swap the code order of dynamic and reflection. Reflection's delay is imperceptible, it's faster than dynamic.
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(a);
will callFoo(Asset)
becausea
is declared asAsset
. – FetishFoo
that differ in their list of parameters. Overloading "is what happens when you have two methods with the same name but different signatures. At compile time, the compiler works out which one it's going to call, based on the compile time types of the arguments and the target of the method call." Matters are different if there was an instance-methodvirtual void Foo
inAsset
and an instance-methodoverride void Foo
inHouse
(Overriding). – Fetishoutsiders static functions
dtb is right – Dilapidateclass Asset { } class House : Asset { } class Program { static void Main() { Asset a = new House(); Foo(a); } static void Foo(Asset a) { Console.WriteLine("Asset"); } static void Foo(House h) { Console.WriteLine("House"); }
. It printsAsset
. Because there is no dispatch are runtime. Just overload resolution at compile time. – FetishFoo((dynamic)a);
I'm thinking what kind of magic is happening under-the-hood of that :-) – Credencecall site
. I was supposed to phraseburned-in instructions at call site
for pondering the kind of magic behinddynamic
:-) – Credence