zoukankan      html  css  js  c++  java
  • 【.NET深呼吸】动态类型(扩充篇)

    前面两文中,老周已向大家介绍了关于动态类型对象的两种级别的使用方案,本篇呢,老周再讲一个自定义动态类型的例子。

    前面给大家演示的例子中,动态类型中包装的是字典类型来存储数据的,这一次咱们换一种风味,老吃酸的不好,这回就吃点辣的吧,火锅就不吃了,据说火锅的汤底里面有罂粟果的皮,吸食微型鸦片不好。

    本例在自定义的动态类型中包装一个XML文档,就用XML来存数据吧。

    还是老方法,从DynamicObject类派生出来。

    这里我主要实现以下几个功能:

    1、可以设置属性,这个是肯定要的,不然怎么赋值数据呢。

            public override bool TrySetMember(SetMemberBinder binder, object value)
            {
                // 查找相应的元素
                var q = from x in xdoc.Root.Elements("item")
                        where ((string)x.Attribute("key")) == binder.Name
                        select x;
                if (q.Count() > 0)
                {
                    // 如果元素存在,就修改
                    XElement ele = q.First();
                    ele.SetAttributeValue("key", value);
                }
                else
                {
                    // 如果元素不存在,就添加
                    XElement ele = new XElement("item");
                    ele.SetAttributeValue("key", binder.Name);
                    ele.SetAttributeValue("value", value.ToString());
                    xdoc.Root.Add(ele);
                }
                return true;
            }

    相信大家还记得,实现不同功能,就是重写不同的虚方法。如果操作成功,就返回true,如果不成功就返回false。在实现中,首先用LINQ筛选XML根下面的item元素,每个item元素存一条数据,元素中key特性表示动态设置的属性名,value表示属性值。也就是说,每个属性的存储结构是这样的:

       <item key = "Age"  value = "105"  />

    2、实现属性的get功能,有了赋值,当然也要允许取值,不然会阴阳失调的。

            public override bool TryGetMember(GetMemberBinder binder, out object result)
            {
                result = string.Empty;
                // 筛选
                var q = from x in xdoc.Root.Elements("item")
                        where ((string)x.Attribute("key")) == binder.Name
                        select x.Attribute("value").Value;
                if (q.Count() > 0)
                {
                    // 取值
                    result = q.First();
                    return true;
                }
                return false;
            }

    原理和上面差不多,用LINQ查出包含指定成员的名字,binder的Name属性就是被调用的动态成员的名字。查询到对应的项后,把值返回。

    3、实现转换功能,想让动态类型支持类型转换,可以重写TryConvert方法。

            public override bool TryConvert(ConvertBinder binder, out object result)
            {
                result = null;
                // 如果是隐式转换,只支持转换为字符串类型
                if (binder.Explicit == false)
                {
                    if (binder.Type != typeof(string))
                    {
                        return false;
                    }
                    result = xdoc.Root.ToString();
                    return true;
                }
                // 如果是显式转换,只支持转换为XElement类型
                else
                {
                    if (binder.Type != typeof(XElement))
                    {
                        return false;
                    }
                    result = xdoc.Root;
                    return true;
                }
    
                return false;
            }

    注意这个binder,它有一个属性叫Explicit,大家还记得老周前不久写过有关自定义转换的烂文,转换有隐式和显示,这个属性如果为true,表明这个动态对象正在被显式转换为其他类型,像这样:

      oo = (string)dynamicObj;

    如果属性为false,就表明正在进行隐式转换,像:

     oo = dynamicObj;

    binder的Type属性表示要转换的目标类型的type,如果要转换为int,那就是typeof(int)。转换后的值赋值给result参数。

    我这里实现的功能是:隐式的话,转换为string;显式的话,转为XElement对象。

    最后,在类中初始化一下包装的XML文档。

            private XDocument xdoc = null;
    
            public MyXmlDynamic()
            {
                // 初始化文档
                xdoc = new XDocument(new XElement("root"));
            }

    好了,这个自定义的动态类型完成了,当然了,接下来就是测试。

                dynamic d = new MyXmlDynamic();
                d.Name = "王老三";
                d.Desc = "大坏蛋";
                d.Age = 55;
    
                Console.WriteLine("Name = {0}, Desc = {1}, Age = {2}", d.Name, d.Desc, d.Age);
    
                // 测试隐转
                string xml = d;
                Console.WriteLine("
    隐式转换为XML字符串:
    " + xml);
    
                // 测试显转
                XElement x = (XElement)d;
                Console.WriteLine("
    
    显式转换为XML元素:
    " + x);

    于是,得到如下结果:

    至此,有关动态类型的话题,老周就讲完了,不知道这位网友看懂否?看不懂也没关系,可以慢慢去研究,多动手干活,就会明白了。编程这玩意儿,很多时候就是依靠动手去试出来的,光读理论没多大用处,更何况,编程是技术性的东西,写再多的理论也没什么用,老周十几年来,一如既往地对编程理论不感兴趣。

    所以,有人就跟老周说,老周,你写的东西太不深入了;老周,你的书太没有深度了。

    反正我不懂什么叫深度,什么叫深入,老周只想着写出来,人人都能看懂。写那么生僻难懂做什么,不就是敲键盘、写代码吗,是吧,搞那么复杂干吗。

    你要是希望老周写点玄学、道学、佛学、儒学、美学、书学相关的文章,那就不同了,那样老周也可以写得很抽象,为啥,因为美学、玄学本来就是抽象。人家庄爷爷说了,不抽象的美都是俗气,抽象的美才是天地大美。

    所以说嘛,写什么样的内容就用什么样的方法,写编程的东西,老周是拒绝抽象的。

    示例源代码下载

  • 相关阅读:
    golang的缓冲channel简单使用
    golang协程同步的几种方法
    红黑树原理详解及golang实现
    go路由httprouter中的压缩字典树算法图解及c++实现
    golang编译源代码和交叉编译方法
    cmake使用笔记
    如何用redis设计数据库初探
    muduo学习笔记(六) 多线程的TcpServer
    利用 Blob 处理 node 层返回的二进制文件流字符串并下载文件
    数据量庞大的分页穿梭框实现
  • 原文地址:https://www.cnblogs.com/tcjiaan/p/5130929.html
Copyright © 2011-2022 走看看