C# 4.0 中的“动态”类型有何用途?

2024-04-10

C# 4.0 引入了一种称为“动态”的新类型。听起来不错,但是程序员会用它做什么呢?

有没有什么情况可以挽救局面?


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 变得更易于使用:

  1. 可选参数
  2. Making refCOM API 可选
  3. 命名参数

上述调用的新语法为:

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。

动态关键字由两部分组成:

  1. C# 中的 new 关键字,dynamic
  2. 一组运行时类,知道如何处理不同类型的对象,并实现特定的 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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# 4.0 中的“动态”类型有何用途? 的相关文章

  • 司机和提供商之间的区别

    数据库中的驱动程序和提供程序有什么区别 有没有解释一下 不胜感激 样本 ADO NET driver for MySQL vs providerName System Data EntityClient 来自 MSDN 论坛 驱动程序是安装
  • 带有运算符语法的错误消息,但不带有函数语法的错误消息

    为什么我在调用 unary 时收到错误消息 使用运算符语法 如果我用函数语法调用它就可以了 现场演示 https godbolt org z j7AbeQ template
  • 为什么需要数字后缀?

    C 语言 我确信还有其他语言 需要在数字文字末尾添加后缀 这些后缀指示文字的类型 例如 5m是一个小数 5f是一个浮点数 我的问题是 这些后缀真的有必要吗 或者是否可以从上下文中推断出文字的类型 例如 代码decimal d 5 0应该推断
  • 将日期时间转换为指定格式

    我有这个日期格式yy MM dd HH mm ss ex 12 02 21 10 56 09 问题是 当我尝试使用以下代码将其转换为不同格式时 CDate 12 02 21 10 56 09 ToString MMM dd yyyy HH
  • 静态类与类的实例

    我有一个静态类 用于访问我的公共属性 整个应用程序的全局属性 和我在应用程序运行期间使用的方法 例如 我在静态类中设置了一些属性 并且在应用程序运行时我可以从属性中获取值 但我可以使用单例模式创建非静态类并以相同的方式使用它 问题 对于我的
  • 子目录中的头文件(例如 gtk/gtk.h 与 gtk-2.0/gtk/gtk.h)

    我正在尝试使用 GTK 构建一个 hello world 其中包括以下行 include
  • 用于连接 DataTable 上的动态列的动态 LINQ

    我目前遇到的情况不确定如何继续 我有两个从数据库填充的数据表 我还有一个可用的列名称列表 可用于将这两个数据表连接在一起 我希望编写一组 LINQ 查询 这些查询将 显示两个数据表中的行 内部联接 用于从一个数据表更新另一个数据表 显示一个
  • 时间:2019-03-17 标签:c++fstream并发访问

    如果从不同的进程 线程同时访问文件会发生什么 据我所知 没有锁定文件的标准方法 只有操作系统特定的功能 就我而言 文件将被经常读取而很少写入 现在如果A打开一个文件进行读取 ifstream 并开始读取块 和B打开相同的文件进行写入 ofs
  • 如何在 C# 中获取 Json 数组?

    我有一个像这样的 Json 字符串 我想将它加载到 C 数组中 当我尝试这样做时 我收到异常 我的字符串 customerInformation customerId 123 CustomerName Age 39 Gender Male
  • 使用多线程进行矩阵乘法?

    我应该使用线程将两个矩阵相乘 有两件事 当我运行程序时 我不断得到 0 我还收到消息错误 对于每个错误 它在粗体行上显示 警告 从不兼容的指针类型传递 printMatrix 的参数1 我尝试打印输出 还要注意 第一个粗体块 这是我解决问题
  • 为什么 f(i = -1, i = -1) 是未定义的行为?

    我正在读关于违反评估顺序 http en cppreference com w cpp language eval order 他们举了一个令我困惑的例子 1 如果标量对象上的副作用相对于同一标量对象上的另一个副作用是无序的 则行为未定义
  • 无法在 C# 中为 EventArgs 分配使用派生类型的事件处理程序

    所以我有一个事件声明如下 public event EventHandler OnChangeDetected 然后我有以下处理程序被分配给该事件 myObject OnChangeDetected OnTableChanged 我的理解是
  • rabbitmq 的 REST API

    有没有办法从 ajax 向 RabbitMQ 发送数据 我的应用程序由数千个 Web 客户端 用 js 编写 和 WCF REST 服务组成 现在我试图弄清楚如何为我的应用程序创建可扩展点 这个想法是有一个rabbitmq实例 它从放置在一
  • 从 NumPy 数组到 Mat 的 C++ 转换 (OpenCV)

    我正在围绕 ArUco 增强现实库 基于 OpenCV 编写一个薄包装器 我试图构建的界面非常简单 Python 将图像传递给 C 代码 C 代码检测标记并将其位置和其他信息作为字典元组返回给 Python 但是 我不知道如何在 Pytho
  • C 语言中的 Alpha 混合 2 RGBA 颜色[重复]

    这个问题在这里已经有答案了 可能的重复 如何快速进行阿尔法混合 https stackoverflow com questions 1102692 how to do alpha blend fast 对 2 个 RGBA 整数 颜色进行
  • Linq.Select() 中的嵌套表达式方法调用

    I use Select i gt new T 每次手动点击数据库后将我的实体对象转换为 DTO 对象 以下是一些示例实体和 DTOS 用户实体 public partial class User public int Id get set
  • printf或iostream如何指定点后的最大位数

    字符串采用什么格式printf or iomanip我应该使用 iostream 中的运算符以以下格式打印浮点数 125 0 gt 125 125 1 gt 125 1 125 12312 gt 125 12 1 12345 gt 1 12
  • 这种尺寸对齐是如何工作的

    对于所提供的评论 我无法理解以下代码 这段代码的作用是什么 以及等效的代码是什么8 aligned segment size must be 4 aligned attr gt options ssize 3 Here ssize is o
  • 将 char 绑定到枚举类型

    我有一段与此非常相似的代码 class someclass public enum Section START MID END vector section Full void ex for int i 0 i section
  • 如何在c linux中收听特定接口上的广播?

    我目前可以通过执行以下操作来收听我编写的简单广播服务器 仅广播 hello int fd socket PF INET SOCK DGRAM 0 struct sockaddr in addr memset addr 0 sizeof ad

随机推荐

  • 读取 ELF 部分的内容(以编程方式)

    我正在尝试检索 ELF 二进制文件中附加部分的内容 此时 我使用以下代码来检索每个部分的名称 include
  • jQuery 验证 - 隐藏错误消息

    我正在使用 jQuery 验证插件 并希望禁用它创建的或元素 容器来显示错误 消息 基本上 我希望带有错误的输入元素具有错误类 但不创建包含错误消息的附加元素 这可能吗 我刚刚想到了 CSS 解决方法 但它并没有真正解决元素仍在创建的事实
  • Spring Cloud Sleuth-获取当前的traceId?

    我正在使用 Sleuth 我想知道是否可以获取当前的 TraceId 我不需要添加任何回复或任何内容 我只想要在某些情况下向开发团队发出警报的电子邮件的traceId Ex import brave Span import brave Tr
  • 如何在 gitlab CI 中检测编译器警告

    在我们的 gitlab 服务器上设置 CI 构建的步骤中 我似乎找不到有关如何设置编译器警告检测的信息 构建输出示例 100 Building CXX object somefile cpp o home gitlab runner bui
  • 将数据从 Dynamodb 发送到 Amazon Elasticsearch 的最佳方式

    我想知道将数据从 dynamoDB 发送到 elasticsearch 的最佳方式是什么 AWS SDK js https github com Stockflare lambda dynamo to elasticsearch blob
  • Android:从另一个活动返回时避免调用 onCreate()

    假设我的应用程序包含两个活动 A 和 B 两者在 AndroidManifest 中都仅限于纵向 活动 A 启动活动 B 在Activity B中 有一个按钮 它调用finish 当点击时 问题是 当我垂直握住设备 纵向 并单击按钮时 调用
  • DT Shiny 中单列的渲染下拉列表

    我不精通 Javascript 并且想复制下拉菜单中提供的功能兰森塔布尔 https jrowen github io rhandsontable dropdown autocomplete包但对于DT https rstudio gith
  • 将 IEnumerable 对象序列化为字符串数组的扩展方法?

    我的最后一个问题是关于将对象的字符串表示形式序列化为 XML https stackoverflow com questions 1138414 can i serialize xml straight to a string instea
  • 为什么我的 dockerfile 不复制目录

    在我的 dockerfile 中我有这两行 ADD ansible inventory etc ansible hosts ADD ansible ansiblerepo 第一行有效 因为我可以运行容器并看到我的主机文件已填充了清单文件中的
  • 使用 getElementsByName() 设置选项值

    拥有这个字段集 fieldset legend death legend fieldset
  • 如何从 javascript 中的 API 调用返回值到 React 组件

    我似乎无法将 javascript 中此 API 调用的值返回到我的 React 组件 我有一个调用 API 的 java 脚本文件 在js文件中 返回结果 但是当我在react组件中调用useEffect中的js函数时 它返回未定义 ex
  • ctags 多行 C 函数原型

    ctags 有没有办法处理 C 中的多行函数原型 我四处寻找 fields S应该做多行原型 但我无法让它工作 ctags x c kinds pf fields S file file int foo int x int y ctags
  • django QueryDict 仅返回列表的最后一个值

    使用 django 1 8 我观察到一些奇怪的事情 这是我的 JavaScript function form submit var form form1 id request post this attr action form seri
  • 面向对象的 CSS:这重要吗? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我刚刚发现这个有趣的演示 http www slideshare net stubbornella object oriented css ty
  • 为什么React需要jsdom来测试?

    在为 React 组件编写测试时 您必须将它们渲染到 DOM 中 以便断言它们的正确性 例如 如果您想测试某个类是否已添加到给定状态的节点 则必须渲染到 DOM 节点 然后通过普通 DOM API 检查该 DOM 节点 问题是 考虑到 Re
  • 使用 C#、LINQ - 想要获取列名和数据值

    我想以一种相当通用的方式显示一行的内容 我将针对几个不同的表使用这种技术 输出将是纯文本 在 RichTextBox 中 如下所示 表名 PROPNUM xxxxxx 销售日期 月 日 年 最后一列 最后一个值 a 我知道每个表的列名 但真
  • 在Vue组件模板中的元素属性中组合字符串和变量

    我有一个表格 其中有 1 个客户或 2 个客户 我创建了一个用于选择计数的组件 另一个用于显示客户端信息表单的组件 因此 如果有 2 个客户端 使用 v for 则有 2 个表单 div div
  • 如何使用 SolrJ 获取突出显示的片段?

    我正在将我的应用程序从 Lucene 迁移到 Solr Solr 可以更好地处理突出显示 但是如果我搜索关键字 city 我会期望得到如下响应 id fdc3833a 0e4f 4314 ba8c title Paris is a beau
  • 异常模块的阴谋导入错误

    我到处搜索都找不到解决这个问题的方法 我正在尝试导入plotly在 Jupyter Notebook 中使用以下代码并分别收到以下错误 Code import sys print sys path sys path append usr l
  • C# 4.0 中的“动态”类型有何用途?

    C 4 0 引入了一种称为 动态 的新类型 听起来不错 但是程序员会用它做什么呢 有没有什么情况可以挽救局面 The dynamic添加了关键字以及 C 4 0 的许多其他新功能 以便更轻松地与具有不同 API 的其他运行时中或来自其他运行