代码改变世界

.Net 4.0 DynamicObject使用(下)

2010-07-11 18:44  Henry Cui  阅读(4195)  评论(0编辑  收藏  举报

上篇文章中我们看过了DynamicObject的基本使用,这篇文章中我们通过Dynamic来实现一个操作xml的动态类型,让我们更为方便的操作xml。

其实在前面的使用ExpandoObject的文章中我们已经,通过ExpandoObject来实现了操作Xml,并体现了动态性,但是不好的是,里面没有Linq to Xml大量Api的支持,操作起来很不方便,同时我们需要编写大量的辅助方法才行。而DynamicObject可以让我们自己决定动态运行时的操作方式,我们可以很快想到通过借助XElement来实现。是的,我的想法就是这样的。

基本实现

来看看我们的Linq to Xml的语法:

            var employee = new XElement(
                "Employee",
                new XElement("Name",
                    new XElement("FirstName","Henry"),
                    new XElement("LastName","Cui")),
                new XElement("Birthday","1987-10-14")
                );

现在我们可以借助DynamicObject来实现一种更为直观更为简洁的语法的创建Xml的方式。

首先我们来顶一个DynamicXNode类型,继承于DynamicObject:

 public class DynamicXNode:DynamicObject
    {
        private XElement _XElement;

        #region Constructor Methods
        public DynamicXNode(string name)
        {
            _XElement = new XElement(name);
        }

        public DynamicXNode(XElement node)
        {
            _XElement = node;
        }
        #endregion
   }

我们来重写下TryGetMember 跟TrySetMember方法:

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

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            var node = _XElement.Element(binder.Name);
            if (node != null)
            {
                node.SetValue(value);
            }
            else
            {
                //是否是复合的类型
                if (value is DynamicXNode)
                {
                    _XElement.Add(new XElement(binder.Name));
                }
                else
                {
                    _XElement.Add(new XElement(binder.Name, value.ToString()));
                }
            }
            return true;
        }

我们来写测试的代码看:

        [TestMethod()]
        public void DynamicXNodesTest()
        {
            dynamic employee = new DynamicXNode("Employee");
            employee.Name = new DynamicXNode("Name");
            employee.Name.FirstName = "Henry";
            employee.Name.LastName = "Cui";
            employee.Birthday = "1987-10-14";
        }

哦,我们还需要借助XElement来把它输出来,在重写下TryConvert方法吧:

        public override bool TryConvert(ConvertBinder binder, out object result)
        {
            if (binder.Type.Equals(typeof(XElement)))
            {
                result = _XElement;
                return true;
            }
            return base.TryConvert(binder, out result);
        }

之后我们输出来可以看到:

image

添加额外的东西

好像已经差不多了,可是我们这里还没有Api的支持啊,我们可以将动态的方法的Invoke通过XElement去Invoke,重写

TryInvokeMember,通过反射机制到XElement上执行吧:

        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
        {
            var ttype = typeof(XElement);
            try
            {
                result = ttype.InvokeMember(binder.Name,
                             BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance,
                             null,
                             _XElement,
                             args);
                return true;
            }
            catch
            {
                result = null;
                return false;
            }
        }

总结

在这篇文章中我们看到了如果使用DynamicObject进行应用了,这里面只是一个xml操作的一个想法,还有许多需要去完善的地方。在.Net4.0中的动态性确实给我们带来了很大的惊喜,已经方便之处。

参考文档

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
作者:Henllyee Cui
出处: http://henllyee.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明。