`

C# - DynamicObject with Dynamic and create wrapper with DynamicObject

    博客分类:
  • C#
阅读更多

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. 

 

 

using System.Collections.Generic;
using System.Dynamic;

namespace DynamicObjectDemo
{
    class DynamicDictionary : DynamicObject
    {
        private Dictionary<string, object> dictionary = new Dictionary<string, object>();


        public int Count
        {
            get { return dictionary.Count; }
        }


        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {

            string name = binder.Name.ToLower();
            return dictionary.TryGetValue(name, out result);
        }

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            dictionary[binder.Name.ToLower()] = value;

            return true;
        }
    }
}

 

 

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

 

 

namespace DynamicObjectDemo
{
    /// <summary>
    /// Main method to test the DynamicObject
    /// </summary>
    /// <remarks>
    /// <para>
    /// Please find references information from: http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject.aspx 
    /// </para>
    /// </remarks>
    class Program
    {
        static void Main(string[] args)
        {

            // you must use the "Dynamic" keyword to create object, otherwise, you won't be able to use get the dynamic behavior

            dynamic person = new DynamicDictionary();


            // adding new Dictionary Properties
            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.
            person.LastName = "Adams";

            //getting values of the dynamic properties
            // the tryGetMember methods is called
            Console.WriteLine(person.FirstName + " " + person.lastname); // this time, we uses the lower case member

            Console.WriteLine("NUmber of dynamic properties" + person.Count);


            try
            {
                // the following will throw Exception at runtime, 
                // when the TryGetMember method return a false, and this causes a 
                // RuntimeBinderException
                Console.WriteLine(person.address);
            }
            catch (RuntimeBinderException ex)
            {
                Debug.WriteLine("caught exception calling person.address: {0}", ex.ToString());
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Some unknown exception : {0}", ex.ToString());
            }
        }
    }
}

 

 

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. 

 

XElement contactXML =
    new XElement("Contact",
    new XElement("Name", "Patrick Hines"),
    new XElement("Phone", "206-555-0144"),
    new XElement("Address",
        new XElement("Street1", "123 Main St"),
        new XElement("City", "Mercer Island"),
        new XElement("State", "WA"),
        new XElement("Postal", "68042")
    )
);

 

 

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

 

dynamic contact = new DynamicXMLNode("Contacts");
contact.Name = "Patrick Hines";
contact.Phone = "206-555-0144";
contact.Address = new DynamicXMLNode();
contact.Address.Street = "123 Main St";
contact.Address.City = "Mercer Island";
contact.Address.State = "WA";
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.

 

using System;
using System.Dynamic;
using System.Reflection;
using System.Xml.Linq;

namespace DynamicObjectDemo
{
    /// <summary>
    /// A wrapper on the XElement
    /// </summary>
    /// <remarks>
    /// <para>
    /// You can find some reference page from 
    ///     * 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 
    /// </para>
    /// </remarks>
    public class DynamicXMLNode : DynamicObject
    {
        XElement node;

        public DynamicXMLNode(XElement node)
        {
            this.node = node;
        }

        public DynamicXMLNode()
        {
            
        }

        public DynamicXMLNode(string name)
        {
            node =new XElement(name);
        }


        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            XElement getNode = node.Element(binder.Name);
            if (getNode != null)
            {
                result = new DynamicXMLNode(getNode);
                return true;
            }
            else
            {
                result = null;
                return false;
            }
        }

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            XElement setNode = node.Element(binder.Name);
            if (setNode != null)
            {
                setNode.SetValue(binder.Name);
            }
            else
            {
                if (value.GetType() == typeof (DynamicXMLNode))
                {
                    node.Add(new XElement(binder.Name));
                }
                else
                {
                    node.Add(new XElement(binder.Name, value));
                }
            }
            return true;
        }

        // 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.
        //   String state = contact.Address.State
        // 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
        public override bool TryConvert(ConvertBinder binder, out object result)
        {
            if (binder.Type == typeof(string))
            {
                result = node.Value;
                return true;
            }
            else
            {
                result = null;
                return false;
            }
        }

        // though we can get manipulate indirectly to XElement values wrapped by the DynamicXMLNode, we can even get the contained result 
        // out of the DynamicXMLNode, we cannot call methods which is suppose to work on XElement, here is what in addition you can 
        // to get Access to XElement methods
        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
        {
            Type xmlType = typeof(XElement);
            try
            {
                result = xmlType.InvokeMember(binder.Name,
                                              BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance,
                                              null,
                                              node,
                                              args);
                return true;
            }
            catch
            {
                result = null;
                return false;
            }
        }
    }
}

 

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

    public class DynamicXMLNodeMain
    {
        public static void DynamicXMLNodeCreateReturnValidDynamixXMLNode()
        {
            dynamic contact = CreateDynamicXMLNode();
            if (contact != null)
            {
                Console.WriteLine("Created DynamicXMLNode ");
            }
            else
            {
                Console.WriteLine("Failed to create DynamicXMLNode");
            }
        }

        public  static void DynamicXMLNodeConvertToStringReturnXElementValue()
        {
            dynamic contact = CreateDynamicXMLNode();
            string state = contact.Address.State;
            Console.WriteLine("State is {0}", state);
        }

        public static void DynamicXMLNodeTryInvokeMemberCallXElementMethods()
        {
            dynamic contact = CreateDynamicXMLNode();
            contact.Address.Postal.SetValue("newPostValue");
            string newPostal = contact.Address.Postal;
            if (newPostal == "newPostValue")
            {
                Console.WriteLine("Set new Post value");
            }
            else
            {
                Console.WriteLine("Failed to set new postal value");
            }
        }

        public static DynamicXMLNode CreateDynamicXMLNode()
        {
            dynamic contact = new DynamicXMLNode("Contacts");
            contact.Name = "Patrick Hines";
            contact.Phone = "206-555-0144";
            contact.Address = new DynamicXMLNode();
            contact.Address.Street = "123 Main St.";
            contact.Address.City = "Mercer Island";
            contact.Address.State = "NA";
            contact.Address.Postal = "68402";
            return contact;
        }
    }

 

and this is the Main method which invoke them.. 

 

        static void Main(string[] args)
        {
            // This is test on the DynamicXMLNode
            DynamicXMLNodeMain.DynamicXMLNodeCreateReturnValidDynamixXMLNode();
            DynamicXMLNodeMain.DynamicXMLNodeConvertToStringReturnXElementValue();
            DynamicXMLNodeMain.DynamicXMLNodeTryInvokeMemberCallXElementMethods();

        }

 

 

References

 

[1] DynamicObject Class:  

[2] Dynamic in C# 4.0: Creating Wrappers with DynamicObject

 

分享到:
评论

相关推荐

    C# Dynamic关键字之:解析dynamic就是Object

    C#中的`dynamic`关键字是C# 4.0引入的一个新特性,它允许程序员在编译时不进行类型检查,而是将类型检查推迟到运行时。`dynamic`的使用主要是为了解决与非.NET Framework的动态语言交互,如IronPython、IronRuby,...

    动态的力量:使用C#中的DynamicObject轻松读取XML和CSV文件

    `Power-of-Dynamic-Reading-XML-and-CSV-files-made-ea.pdf`这个文件可能是详细教程或文档,它可能包含更具体的实现步骤和示例代码,帮助开发者理解如何结合`DynamicObject`与XML和CSV读取。 总之,通过使用C#中的`...

    C#中的动态类型(Dynamic)的项目工程

    在C#编程语言中,动态类型(Dynamic)是一种强大的特性,它允许程序员在运行时进行类型检查和操作。这个特性引入自C# 4.0版本,为开发者提供了更大的灵活性,尤其是在处理非强类型的数据或者与动态语言如Python、...

    C#动态对象(dynamic)详解(实现方法和属性的动态)

    C#中的动态对象`dynamic`关键字允许在运行时执行类型检查和绑定,使得代码更加灵活。下面我们将深入探讨`dynamic`的使用、属性实现以及如何模拟动态方法。 首先,`dynamic`关键字的主要目的是为了简化与非.NET框架...

    C#使用dynamic类型访问JObject对象

    C# 使用 dynamic 类型访问 JObject 对象 C# 使用 dynamic 类型访问 JObject 对象是指在 C# 语言中使用 dynamic 关键字来访问 Newtonsoft.Json 库中的 JObject 对象。JObject 是一个可以用来表示 JSON 对象的类,它...

    C#中dynamic关键字的正确用法(推荐)

    dynamic的出现让C#具有了弱语言类型的特性。编译器在编译的时候不再对类型进行检查,编译期默认dynamic对象支持你想要的任何特性。比如,即使你对GetDynamicObject方法返回的对象一无所知,你也可以像如下那样进行...

    C# Dynamic之:ExpandoObject,DynamicObject,DynamicMetaOb的应用(上)

    在C#编程语言中,动态类型(Dynamic)提供了一种在运行时创建和操作对象的新方式,使得开发者能够在不完全了解对象结构的情况下进行交互。本文将深入探讨三个与动态类型相关的关键概念:ExpandoObject、...

    c#中使用动态类的样例程序

    当对动态对象进行操作时,如果运行时类型不匹配或方法不存在,将会抛出`System.Dynamic.DynamicObject+MissingMemberException`或`System.MissingMethodException`异常。因此,在使用动态类型时,一定要做好异常...

    DynamicObject.java

    支持在原对象新增属性并赋值,可创建动态的Object对象

    c# 4.0新特性详解

    其中最显著的变化是动态类型支持,通过`dynamic`关键字的引入,使得C#能更好地与其他动态语言如JavaScript和Python进行交互。 动态类型(Dynamic Typing)是C# 4.0中的核心特性之一。在C# 3.0及以前的版本中,如果...

    C#_ReoScript脚本引擎Demo-包源代码

    C# ReoScript脚本引擎是一个强大的工具,用于在C#环境中执行和集成脚本代码。这个Demo包提供了源代码,使得开发者可以深入理解其工作原理,并根据需求进行定制和扩展。ReoScript引擎旨在提高开发效率,允许快速实现...

    使用DynamicObject实施常规代理类

    在提供的压缩包文件中,"Using-DynamicObject-to-Implement-General-Proxy-Cla.pdf"可能包含了更详细的实现和示例,而"dynamicobjectproxy_src_1_1.zip"可能包含了一个实际的项目源代码,供读者学习和参考。...

    [C_#4.0本质论(第3版)].(Essential.C#4.0).Mark.Michaelis.文字版

    2. **动态类型**:C# 4.0引入了`dynamic`关键字,允许在运行时进行类型绑定,使得与动态语言的交互变得更加便捷,如与Python或JavaScript等的集成。 3. **多线程和并发**:C# 4.0提供了Task Parallel Library (TPL)...

Global site tag (gtag.js) - Google Analytics