C# - DynamicObject with Dynamic

简介: 本文转载:http://joe-bq-wang.iteye.com/blog/1872756 里面有动态Linq to xml的写法。 There is a expando object which allow you add/remove properties at runtime, Dyna...

本文转载:http://joe-bq-wang.iteye.com/blog/1872756

里面有动态Linq to xml的写法。

There is a expando object which allow you add/remove properties at runtime, DynamicObject provides ou with more capability and it is better used in places where a wrapper excels a raw XML file or script object syntax. 


First, we will intoduce the  DynamicObject, as stated in the References Section on "DynamicObject Class",which defines some methods such as TryGetMember, TrySetMember, TryInvokeMembers which acts as a proxy to the real value contained in the DynamicObject derived classes. Also, DynamicObject has special support from the DLR (Dynamic Language Runtime) which means it has some special translation when you use DynamicObject with "dynamic" keyword. 

 

First, we will see a example object with DynamicObject which has the ability to let you query/set values in case-insensitive fashion, which the real data is backed by a Dictionary. 

 

 

C#代码   收藏代码
  1. using System.Collections.Generic;  
  2. using System.Dynamic;  
  3.   
  4. namespace DynamicObjectDemo  
  5. {  
  6.     class DynamicDictionary : DynamicObject  
  7.     {  
  8.         private Dictionary<string, object> dictionary = new Dictionary<string, object>();  
  9.   
  10.   
  11.         public int Count  
  12.         {  
  13.             get { return dictionary.Count; }  
  14.         }  
  15.   
  16.   
  17.         public override bool TryGetMember(GetMemberBinder binder, out object result)  
  18.         {  
  19.   
  20.             string name = binder.Name.ToLower();  
  21.             return dictionary.TryGetValue(name, out result);  
  22.         }  
  23.   
  24.         public override bool TrySetMember(SetMemberBinder binder, object value)  
  25.         {  
  26.             dictionary[binder.Name.ToLower()] = value;  
  27.   
  28.             return true;  
  29.         }  
  30.     }  
  31. }  

 

 

and here is a test program to show you how to use the DynamicDictionary class. 

 

 

C#代码   收藏代码
  1. namespace DynamicObjectDemo  
  2. {  
  3.     /// <summary>  
  4.     /// Main method to test the DynamicObject  
  5.     /// </summary>  
  6.     /// <remarks>  
  7.     /// <para>  
  8.     /// Please find references information from: http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject.aspx   
  9.     /// </para>  
  10.     /// </remarks>  
  11.     class Program  
  12.     {  
  13.         static void Main(string[] args)  
  14.         {  
  15.   
  16.             // you must use the "Dynamic" keyword to create object, otherwise, you won't be able to use get the dynamic behavior  
  17.   
  18.             dynamic person = new DynamicDictionary();  
  19.   
  20.   
  21.             // adding new Dictionary Properties  
  22.             person.FirstName = "Ellen";  //  the dynamic language runtime (DLR) first uses the language binder to look for a static definition of a property in the class. If there is no such property, the DLR calls the TrySetMember method.  
  23.             person.LastName = "Adams";  
  24.   
  25.             //getting values of the dynamic properties  
  26.             // the tryGetMember methods is called  
  27.             Console.WriteLine(person.FirstName + " " + person.lastname); // this time, we uses the lower case member  
  28.   
  29.             Console.WriteLine("NUmber of dynamic properties" + person.Count);  
  30.   
  31.   
  32.             try  
  33.             {  
  34.                 // the following will throw Exception at runtime,   
  35.                 // when the TryGetMember method return a false, and this causes a   
  36.                 // RuntimeBinderException  
  37.                 Console.WriteLine(person.address);  
  38.             }  
  39.             catch (RuntimeBinderException ex)  
  40.             {  
  41.                 Debug.WriteLine("caught exception calling person.address: {0}", ex.ToString());  
  42.             }  
  43.             catch (Exception ex)  
  44.             {  
  45.                 Debug.WriteLine("Some unknown exception : {0}", ex.ToString());  
  46.             }  
  47.         }  
  48.     }  
  49. }  

 

 

With DynamicObject, you can do even more, suppose that we have an XElement and we know we can create an XElement with some syntax as below. 

 

C#代码   收藏代码
  1. XElement contactXML =  
  2.     new XElement("Contact",  
  3.     new XElement("Name", "Patrick Hines"),  
  4.     new XElement("Phone", "206-555-0144"),  
  5.     new XElement("Address",  
  6.         new XElement("Street1", "123 Main St"),  
  7.         new XElement("City", "Mercer Island"),  
  8.         new XElement("State", "WA"),  
  9.         new XElement("Postal", "68042")  
  10.     )  
  11. );  

 

 

however, we can make it even simpler. what we have in mind is something like this: 

 

Haskell代码   收藏代码
  1. dynamic contact = new DynamicXMLNode("Contacts");  
  2. contact.Name = "Patrick Hines";  
  3. contact.Phone = "206-555-0144";  
  4. contact.Address = new DynamicXMLNode();  
  5. contact.Address.Street = "123 Main St";  
  6. contact.Address.City = "Mercer Island";  
  7. contact.Address.State = "WA";  
  8. contact.Address.Postal = "68402";  

 

 

we might need to write Dyanmic Extended class  with the following override.s 

 

TryGetMember : the Contact.Address.Street part in the Contact.Address.Street statement (the part to get some member back) 

TrySetMember: contact.Name = "Patrick Hines";

TryConvert: contact.Name = "Patrick Hines"; (Expected value type is String, but returned type is a DynamicXMLNode)

TryInvokeMember: we have hide the XElement , this enables us to the hidden methods supported by the Xlement

 

here is the full code of the implementation of DynamicXMLNode.

 

C#代码   收藏代码
  1. using System;  
  2. using System.Dynamic;  
  3. using System.Reflection;  
  4. using System.Xml.Linq;  
  5.   
  6. namespace DynamicObjectDemo  
  7. {  
  8.     /// <summary>  
  9.     /// A wrapper on the XElement  
  10.     /// </summary>  
  11.     /// <remarks>  
  12.     /// <para>  
  13.     /// You can find some reference page from   
  14.     ///     * Dynamic in C# 4.0: Creating Wrappers with DynamicObject:  http://blogs.msdn.com/b/csharpfaq/archive/2009/10/19/dynamic-in-c-4-0-creating-wrappers-with-dynamicobject.aspx   
  15.     /// </para>  
  16.     /// </remarks>  
  17.     public class DynamicXMLNode : DynamicObject  
  18.     {  
  19.         XElement node;  
  20.   
  21.         public DynamicXMLNode(XElement node)  
  22.         {  
  23.             this.node = node;  
  24.         }  
  25.   
  26.         public DynamicXMLNode()  
  27.         {  
  28.               
  29.         }  
  30.   
  31.         public DynamicXMLNode(string name)  
  32.         {  
  33.             node =new XElement(name);  
  34.         }  
  35.   
  36.   
  37.         public override bool TryGetMember(GetMemberBinder binder, out object result)  
  38.         {  
  39.             XElement getNode = node.Element(binder.Name);  
  40.             if (getNode != null)  
  41.             {  
  42.                 result = new DynamicXMLNode(getNode);  
  43.                 return true;  
  44.             }  
  45.             else  
  46.             {  
  47.                 result = null;  
  48.                 return false;  
  49.             }  
  50.         }  
  51.   
  52.         public override bool TrySetMember(SetMemberBinder binder, object value)  
  53.         {  
  54.             XElement setNode = node.Element(binder.Name);  
  55.             if (setNode != null)  
  56.             {  
  57.                 setNode.SetValue(binder.Name);  
  58.             }  
  59.             else  
  60.             {  
  61.                 if (value.GetType() == typeof (DynamicXMLNode))  
  62.                 {  
  63.                     node.Add(new XElement(binder.Name));  
  64.                 }  
  65.                 else  
  66.                 {  
  67.                     node.Add(new XElement(binder.Name, value));  
  68.                 }  
  69.             }  
  70.             return true;  
  71.         }  
  72.   
  73.         // TryGetMember always returns an instance of DynamicXMLNode. How do I get the actual value of the XML node? For example, I want the following line to work, but now it throws an exception.  
  74.         //   String state = contact.Address.State  
  75.         // one option is to return the actual values for leaf nodes, but to explore another option: you can try the type conversion, just add the following method to the DynaxmicXMLNode class  
  76.         public override bool TryConvert(ConvertBinder binder, out object result)  
  77.         {  
  78.             if (binder.Type == typeof(string))  
  79.             {  
  80.                 result = node.Value;  
  81.                 return true;  
  82.             }  
  83.             else  
  84.             {  
  85.                 result = null;  
  86.                 return false;  
  87.             }  
  88.         }  
  89.   
  90.         // though we can get manipulate indirectly to XElement values wrapped by the DynamicXMLNode, we can even get the contained result   
  91.         // out of the DynamicXMLNode, we cannot call methods which is suppose to work on XElement, here is what in addition you can   
  92.         // to get Access to XElement methods  
  93.         public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)  
  94.         {  
  95.             Type xmlType = typeof(XElement);  
  96.             try  
  97.             {  
  98.                 result = xmlType.InvokeMember(binder.Name,  
  99.                                               BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance,  
  100.                                               null,  
  101.                                               node,  
  102.                                               args);  
  103.                 return true;  
  104.             }  
  105.             catch  
  106.             {  
  107.                 result = null;  
  108.                 return false;  
  109.             }  
  110.         }  
  111.     }  
  112. }  

 

to give an impression on the capability that the DynamixXMLNode has empowered us, let 'see the test code below. 

C#代码   收藏代码
  1. public class DynamicXMLNodeMain  
  2. {  
  3.     public static void DynamicXMLNodeCreateReturnValidDynamixXMLNode()  
  4.     {  
  5.         dynamic contact = CreateDynamicXMLNode();  
  6.         if (contact != null)  
  7.         {  
  8.             Console.WriteLine("Created DynamicXMLNode ");  
  9.         }  
  10.         else  
  11.         {  
  12.             Console.WriteLine("Failed to create DynamicXMLNode");  
  13.         }  
  14.     }  
  15.   
  16.     public  static void DynamicXMLNodeConvertToStringReturnXElementValue()  
  17.     {  
  18.         dynamic contact = CreateDynamicXMLNode();  
  19.         string state = contact.Address.State;  
  20.         Console.WriteLine("State is {0}", state);  
  21.     }  
  22.   
  23.     public static void DynamicXMLNodeTryInvokeMemberCallXElementMethods()  
  24.     {  
  25.         dynamic contact = CreateDynamicXMLNode();  
  26.         contact.Address.Postal.SetValue("newPostValue");  
  27.         string newPostal = contact.Address.Postal;  
  28.         if (newPostal == "newPostValue")  
  29.         {  
  30.             Console.WriteLine("Set new Post value");  
  31.         }  
  32.         else  
  33.         {  
  34.             Console.WriteLine("Failed to set new postal value");  
  35.         }  
  36.     }  
  37.   
  38.     public static DynamicXMLNode CreateDynamicXMLNode()  
  39.     {  
  40.         dynamic contact = new DynamicXMLNode("Contacts");  
  41.         contact.Name = "Patrick Hines";  
  42.         contact.Phone = "206-555-0144";  
  43.         contact.Address = new DynamicXMLNode();  
  44.         contact.Address.Street = "123 Main St.";  
  45.         contact.Address.City = "Mercer Island";  
  46.         contact.Address.State = "NA";  
  47.         contact.Address.Postal = "68402";  
  48.         return contact;  
  49.     }  
  50. }  

 

and this is the Main method which invoke them.. 

 

C#代码   收藏代码
  1. static void Main(string[] args)  
  2. {  
  3.     // This is test on the DynamicXMLNode  
  4.     DynamicXMLNodeMain.DynamicXMLNodeCreateReturnValidDynamixXMLNode();  
  5.     DynamicXMLNodeMain.DynamicXMLNodeConvertToStringReturnXElementValue();  
  6.     DynamicXMLNodeMain.DynamicXMLNodeTryInvokeMemberCallXElementMethods();  
  7.   
  8. }  

 

目录
相关文章
C#-数据类型(dynamic)
C#-数据类型(dynamic)
145 0
|
传感器 开发框架 JSON
聊聊 C# dynamic 类型,并分享一个将 dynamic 类型变量转为其它类型的技巧和实例
聊聊 C# dynamic 类型,并分享一个将 dynamic 类型变量转为其它类型的技巧和实例
656 0
|
缓存
艾伟:C#4.0初探:dynamic 关键字
C#新增了dynamic关键字,正因为这一个小小的关键字,C#动态特性向前迈进了一大步。dynamic是一个类型关键字,声明为dynamic的类型与"静态类型"(这里的静态类型是指编译时确定的类型,下同)相比最大的特点它是"动态类型",它会运行时尝试调用方法,这些方法的存在与否不是在编译时检查的,而是在运行时查找,如果方法存在并且参数正确,会正常调用,否则会抛出Microsoft.CSharp.RuntimeBinder.RuntimeBinderException异常。
964 0
|
存储 API 调度
一起谈.NET技术,了解 C# 4 中的 Dynamic 关键字
  dynamic 关键字和动态语言运行时 (DLR) 是 C# 4 和 Microsoft .NET Framework 4 中的重大新增功能。 这些功能在宣布时就引起了人们的极大兴趣,并伴随着许多疑问。
1792 0
|
存储 API 调度
了解 C# “.NET研究”4 中的 Dynamic 关键字
  dynamic 关键字和动态语言运行时 (DLR) 是 C# 4 和 Microsoft .NET Framework 4 中的重大新增功能。 这些功能在宣布时就引起了人们的极大兴趣,并伴随着许多疑问。
1323 0
|
JSON C# 数据格式
C# 使用dynamic类型来访问JObject对象
原文:C# 使用dynamic类型来访问JObject对象 dynamic是C#里面的动态类型,可在未知类型的情况访问对应的属性,非常灵活和方便。 使用Json.Net可以把一个Json字符串转换成一个JObject对象,如果有已知强类型,如果有已知对应的强类型,可以直接转成对应的类型。
1506 0