C#4.0中的动态:使用DynamicObject创建包装

Visual Studio博客

上一个帖子我展示了如何使用新的动态特性和展开对象类在运行时添加和删除属性,以及如何使代码比使用LINQ to XML语法编写的代码更具可读性和灵活性。

但这个例子中有一些明显的缺陷:展开对象LINQ to XML提供了更好的语法,它提供了许多有用的库方法,帮助您处理XML文件。那么,有没有可能将这两个优点结合起来,以获得更好的语法,同时仍然获得所有这些方法?答案是肯定的,但您需要从系统。动态命名空间:动态对象.

这个动态对象类使您能够重写诸如获取或设置成员、调用方法或执行任何二进制、一元或类型转换操作等操作。为了说明这个问题,让我们创建一个覆盖“get-property”操作的非常简单的对象,这样无论何时访问属性,它都会以字符串的形式返回属性的名称。这个示例没有实际价值。

公众阶级采样对象(SampleObject):动态对象{公共重写boolTryGet成员(获取成员绑定器粘合剂,输出对象结果){结果=活页夹。名称;返回true;}}

与相同展开对象,我们必须使用动态关键字创建此类的实例。

动态对象=新的采样对象(SampleObject)();慰问.WriteLine(obj.SampleProperty);//打印“SampleProperty”。

让我们看看这个例子中发生了什么。当你打电话时对象.示例属性,的动态语言运行库(DLR)使用语言绑定器在采样对象(SampleObject)类。如果没有此类属性,DLR将调用TryGet成员方法。此方法通过粘合剂参数。正如你所见粘合剂。姓名包含属性的实际名称。

这个TryGet成员方法返回真的如果操作成功。但运算的实际结果必须分配给out参数结果。在本例中,TryGet成员收益真的,但是对象.示例属性返回“SampleProperty”。

现在,让我们转到一个更复杂的示例,并为X元素对象。我将再次尝试为以下LINQ to XML示例提供更好的语法。

X元素联系人XML=新的X元素(“联系人”,新的X元素(“姓名”,“帕特里克·海因斯”),新的X元素(“电话”,"206-555-0144"),新的X元素(“地址”,新的X元素(“街道1”,“主大街123号”),新的X元素(“城市”,“默瑟岛”),新的X元素(“状态”,“WA”(西澳大利亚州)),新的X元素(“邮政”,"68042")));

首先,我需要创建一个展开对象。我仍然希望能够动态添加和删除属性。但由于我本质上是为X元素类型,我会使用X元素而不是字典来维护属性。

公众阶级DynamicXML节点:动态对象{X元素节点;公众的动态XML节点(X元素节点){.node=节点;}公众的动态XML节点(){}公众的动态XML节点(字符串姓名){节点=新的X元素(名称);}公共重写boolTrySet成员(设置成员绑定器粘合剂,对象值){X元素setNode=节点。元素(活页夹名称);如果(setNode=无效的)setNode(设置节点)。SetValue(值);其他的{如果(value.GetType())==类型(动态XML节点))节点。添加(新的X元素(活页夹名称);其他的节点。添加(新的X元素(活页夹名称,值);}返回true;}公共重写boolTryGet成员(
获取成员绑定器粘合剂,输出对象结果){X元素getNode=节点。元素(活页夹名称);如果(获取节点=无效的){结果=新的动态XML节点(获取节点);返回true;}其他的{结果=无效的;返回false;}}}

下面是如何使用这个类。

动态触点=新的动态XML节点(“联系人”);联系人。姓名=“帕特里克·海因斯”;联系人。电话="206-555-0144";联系人。地址=新的动态XML节点();联系人。地址。街道=“主大街123号”;联系人。地址。城市=“默瑟岛”;联系人。地址。州=“WA”(西澳大利亚州);联系人。地址。邮政="68402";

让我们看看接触对象。创建此对象时,它会初始化其内部X元素。如果设置属性值,如联系人。电话=“206-555-0144”,的TrySet成员方法检查其中是否存在名为Phone的元素X元素。如果它不存在,则该方法创建元素。

接下来有趣的一行是联系人。地址=新的DynamicXML节点().基本上,在这个特定的示例中,这一行意味着我要创建一个具有子节点的节点。对于此属性TrySet成员方法创建X元素没有值。

这里最复杂的情况是一行,例如联系人。地址。州=“WA”(西澳大利亚州).首先TryGet成员方法被调用联系人。地址并返回一个新的DynamicXML节点对象,该对象由X元素名称为Address。(理论上,我本可以退回X元素但这会使示例更加复杂。)然后TrySet成员方法。该方法在中查找State元素联系人。地址。如果找不到,则创建它。

因此,我成功地创建了所需的XML结构。但是TryGet成员始终返回的实例动态XML节点。如何获取XML节点的实际值?例如,我想让下面的行工作,但现在它抛出了一个异常。

字符串状态=联系人。地址。国家;

我有几个选择。我可以修改TryGet成员方法返回叶节点的实际值。但让我们探索另一个选项:覆盖类型转换。只需将以下方法添加到DynamicXML节点类。

公共重写bool尝试转换(转换活页夹粘合剂,输出对象结果){如果(活页夹.类型==类型(字符串)){结果=节点。价值;返回true;}其他的{结果=无效的;返回false;}}

现在,每当我对动态XML节点类型尝试转换方法。该方法检查对象转换为什么类型,如果该类型是字符串,该方法返回内部X元素。否则,返回,这意味着该语言应该确定下一步要做什么(在大多数情况下,这意味着您将得到一个运行时异常)。

我要展示的最后一件事是如何访问X元素方法。让我们覆盖TryInvoke成员方法,以便将所有方法调用重定向到其X元素对象。当然,我正在使用系统。反思命名空间。

公共重写boolTryInvoke成员(调用MemberBinder粘合剂,
对象[]参数,
输出对象结果){类型xml类型=类型(X元素);尝试{结果=xmlType。调用成员(活页夹。姓名,绑定标志。调用方法|绑定标志。公共|绑定标志。实例,无效的,节点,参数);返回true;}抓住{结果=无效的;返回false;}}

此方法使您能够调用X元素的任何节点上的方法动态XML节点对象。这里最明显的缺点是缺少IntelliSense。

我甚至不打算假装这个示例是LINQ to XML库的现成包装器。它不支持属性,不允许创建节点集合(例如,多个联系人),并且可能缺少其他功能。创建库是一项困难的任务,创建一个好的包装器也是如此。但我希望在阅读完这篇博客文章后,您可以使用动态对象你自己。

因此,如果您经常使用具有复杂语法的库来爬行XML文件或处理脚本对象,或者如果您自己创建这样的库,您可能应该考虑编写包装器。这样做可能会使您的工作效率更高,库的语法也会更好。

本文中提供的所有示例都适用于刚刚发布的Visual Studio 2010 Beta 2。如果您有任何意见或建议,欢迎在此处发布或联系DLR团队网址:http://www.codeplex.com/dlr。您也可以通过以下地址向DLR团队发送电子邮件:dlr@microsoft.com.

文档动态对象也可以在MSDN上找到(请查看我们的新MSDN设计,不要忘记查看轻量级视图.)在文档中,您可以阅读该类的其他有用方法,例如尝试二进制操作,TryUnary操作,TrySetIndex(尝试设置索引)、和尝试获取索引.

0条评论

讨论结束。

反馈usabilla图标