我有这些课程:
class Asset
{ }
class House:Asset
{ }
考虑这些局外人的静态功能:
static void Foo (Asset a) { }
static void Foo (House h) { }
如果我写:
House h = new House (...);
Foo(h);
它将调用Foo(House)
(编译时绑定)
如果我写:
Asset a = new House (...);
Foo(a);
它将调用Foo(Asset)
(编译时绑定)
目标:访问运行时类型方法:
我有两个选择:
1)使用动态如下:
Asset a = new House (...);
Foo ((dynamic)a); // NOW it will call Foo(House)
2)使用static
将功能从override
移至polymorphism mechanism
。
问题:
是否有其他方式(不将功能移至polymorphism mechanism
|| dynamic
)?
答案 0 :(得分:9)
目标:访问运行时类型方法
那是dynamic
关键字的用途。它实际上是一个非常干净的&快速做多次派遣。
Multiple Dispatch的最终选项是
dynamic
if (x is House) ... else if(x is Asset)...
问题:还有其他方法吗(没有将函数移动到多态机制|| dynamic)?
所以,是的,当你可以使用快速,不易出错且真正clean syntax wise dynamic
的{{1}}时,有很多方法需要你做很多工作。
答案 1 :(得分:1)
我认为这是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.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 {
}
输出:
Hei
Asset
House
int
这将调用Foo overload int,即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
鉴于C#4中已经有dynamic
功能,我会很难使用反射,除非开发人员仍在使用C#3。所以,使用动态方法代替: - )
<强>更新强>
对于它的价值,dynamic
慢(至少在Mono上),当我运行此代码时,在字母“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 {
}
答案 2 :(得分:1)
如果你想要静态入口点,但你也想要多态行为,那么最简单的混合就是使用单例模式。它将为您提供静态入口点,它返回的对象将具有多态方法。
我还建议忽略每个人说单身人士是一件可怕的坏事。 Prima Donna单身人士的悲惨讲道是中级开发人员的蠢货。单身只是一种工具,如果它符合您的需求 - 那么就使用它。