The dynamic
添加了关键字以及 C# 4.0 的许多其他新功能,以便更轻松地与具有不同 API 的其他运行时中或来自其他运行时的代码进行交互。
举个例子。
如果您有一个 COM 对象,例如Word.Application
对象,并且想要打开一个文档,该方法要做的事情带有不少于15个参数,其中大部分是可选的。
要调用这个方法,你需要这样的东西(我正在简化,这不是实际的代码):
object missing = System.Reflection.Missing.Value;
object fileName = "C:\\test.docx";
object readOnly = true;
wordApplication.Documents.Open(ref fileName, ref missing, ref readOnly,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing);
注意到所有这些论点了吗?您需要传递这些参数,因为 4.0 版本之前的 C# 没有可选参数的概念。在 C# 4.0 中,通过引入以下内容,COM API 变得更易于使用:
- 可选参数
- Making
ref
COM API 可选
- 命名参数
上述调用的新语法为:
wordApplication.Documents.Open(@"C:\Test.docx", ReadOnly: true);
看看它看起来多么容易,可读性如何?
让我们把它分开:
named argument, can skip the rest
|
v
wordApplication.Documents.Open(@"C:\Test.docx", ReadOnly: true);
^ ^
| |
notice no ref keyword, can pass
actual parameter values instead
神奇的是,C# 编译器现在将注入必要的代码,并在运行时使用新类,完成与之前几乎完全相同的操作,但语法已对您隐藏,现在您可以专注于what,并没有那么多how。安德斯·海尔斯伯格喜欢说你必须调用不同的“咒语”,这是对整个事情的魔力的一种双关语,你通常必须挥动你的手并以正确的顺序说出一些魔咒使某种类型的咒语生效。与 COM 对象对话的旧 API 方式有很多,您需要跳过很多环节才能哄骗编译器为您编译代码。
在 4.0 版本之前的 C# 中,如果您尝试与没有接口或类的 COM 对象通信,情况会更加糟糕,您拥有的只是一个IDispatch
参考。
如果你不知道它是什么,IDispatch
基本上是 COM 对象的反射。与IDispatch
您可以询问对象“Save 方法的 id 号是多少”,并构建包含参数值的某种类型的数组,最后调用Invoke
方法上的IDispatch
接口来调用该方法,传递您设法收集到的所有信息。
上面的 Save 方法可能如下所示(这绝对不是正确的代码):
string[] methodNames = new[] { "Open" };
Guid IID = ...
int methodId = wordApplication.GetIDsOfNames(IID, methodNames, methodNames.Length, lcid, dispid);
SafeArray args = new SafeArray(new[] { fileName, missing, missing, .... });
wordApplication.Invoke(methodId, ... args, ...);
所有这一切只是为了打开一个文档。
VB 很久以前就有了可选参数并支持其中大部分开箱即用,所以这个 C# 代码:
wordApplication.Documents.Open(@"C:\Test.docx", ReadOnly: true);
基本上,C# 在表达能力方面赶上 VB,但以正确的方式进行,使其可扩展,而不仅仅是 COM。当然,这也适用于 VB.NET 或构建在 .NET 运行时之上的任何其他语言。
您可以找到有关的更多信息IDispatch
接口开启维基百科:IDispatch http://en.wikipedia.org/wiki/IDispatch如果你想了解更多相关内容。这真是血淋淋的事情。
但是,如果您想与 Python 对象对话怎么办?有一种与用于 COM 对象的 API 不同的 API,并且由于 Python 对象本质上也是动态的,因此您需要借助反射魔法来找到要调用的正确方法及其参数等,但 .NET 则不然。反射,为 Python 编写的东西,与上面的 IDispatch 代码非常相似,只是完全不同。
那么鲁比呢?仍然是不同的 API。
JavaScript?同样的交易,也有不同的 API。
动态关键字由两部分组成:
- C# 中的 new 关键字,
dynamic
- 一组运行时类,知道如何处理不同类型的对象,并实现特定的 API,
dynamic
关键字 require,并将调用映射到正确的处理方式。 API 甚至已记录,因此如果您有来自未涵盖的运行时的对象,您可以添加它。
The dynamic
但是,关键字并不意味着替换任何现有的仅 .NET 代码。相信你can这样做,但由于这个原因它没有被添加,而 C# 编程语言的作者(前面的 Anders Hejlsberg)一直非常坚定地认为他们仍然将 C# 视为强类型语言,并且不会牺牲这一原则。
这意味着尽管您可以编写如下代码:
dynamic x = 10;
dynamic y = 3.14;
dynamic z = "test";
dynamic k = true;
dynamic l = x + y * z - k;
并让它编译,它并不是一种神奇的“让我们在运行时弄清楚你的意思”类型的系统。
整个目的是让与其他类型的对象交谈变得更容易。
互联网上有大量关于关键词、支持者、反对者、讨论、咆哮、赞扬等的材料。
我建议您从以下链接开始,然后通过谷歌搜索了解更多信息:
- DevDays 2010:Anders Hejlsberg - C# 4.0 及更高版本 http://channel9.msdn.com/posts/matthijs/C-40-and-beyond-by-Anders-Hejlsberg/
- 频道 9:Mads Torgersen - C# 4.0 内部:动态类型 + + http://channel9.msdn.com/shows/Going+Deep/Inside-C-40-dynamic-type-optional-parameters-more-COM-friendly/
- DevX:COM 互操作在 C# 4.0 中变得更好 http://www.devx.com/dotnet/Article/42590
- Scott Hanselman - C# 4 和动态关键字 - 围绕 .NET 4(和 Visual Studio 2010)Beta 1 的旋风之旅 http://www.hanselman.com/blog/C4AndTheDynamicKeywordWhirlwindTourAroundNET4AndVisualStudio2010Beta1.aspx