动手实现扩展属性为对象动态添加获取数据(续)

上一篇文章中我们了解了扩展属性的原理和结构,其实其内部结构与思想都与WPF中的依赖属性基本相同,大家也可以从中了解到关于依赖属性的原理,这对了解及使用依赖属性也是有很大的帮助的,“扩展属性”只是针对特定场景做了部分扩展(如支持普通类型对象的扩展属性定义),但是其原理上讲属性都在外部保存,这样就带来一个问题就是不能及时的对对象属性进行回收释放,及需要手动释放(这里不知道有没有什么好的解决办法)。

下面我将继续介绍关于扩展属性动态性的相关问题。

还记得上一篇文章中是怎么使用扩展属性的动态性接口的吗?

   1:  var user1 = new UserInfo1() { Age = 21, Name = "maxzhang1" };
   2:  dynamic dyuser = user1.ToDynamicAttachObject();
   3:  rrr=  dyuser.Info;
   4:  dyuser.Info = 1;
   5:  int d = dyuser.Info;

<!-- .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } -->

关于dynamic类型这里推荐两篇文章 12  。接下来看看我们在扩展属性中是怎么定义动态性的:

1: public class ExtendDynamicObject : DynamicObject
   2: {
   3:     private ExtendObject extendObject;
   4:  
   5:     public ExtendDynamicObject(ExtendObject exObject)
   6:     {
   7:         extendObject = exObject;
   8:     }
   9:  
  10:     public override bool TrySetMember(SetMemberBinder binder, object value)
  11:     {
  12:         string propertyName = binder.Name;
  13:  
  14:         if (this.extendObject.IsExtendProperty(propertyName))
  15:             this.extendObject.SetValue(binder.Name, value);
  16:         else
  17:         {
  18:             object owner = this.extendObject.GetOwner();
  19:             Type ownerType = owner.GetType();
  20:             var propertyInfo = ownerType.GetProperty(propertyName);
  21:             propertyInfo.SetValue(owner, value, null);
  22:         }
  23:         return true;
  24:     }
  25:  
  26:     public override bool TryGetMember(GetMemberBinder binder, out object result)
  27:     {
  28:         result = null;
  29:  
  30:         string propertyName = binder.Name;
  31:  
  32:         if (this.extendObject.IsExtendProperty(propertyName))
  33:             result = this.extendObject.GetValue(binder.Name);
  34:         else
  35:         {
  36:             object owner = this.extendObject.GetOwner();
  37:             Type ownerType = owner.GetType();
  38:             var propertyInfo = ownerType.GetProperty(propertyName);
  39:             propertyInfo.GetValue(owner, null);
  40:         }
  41:         return true;
  42:     }
  43:  
  44: }

其实就是注入一个ExtendObject类型的对象然后动态的把属性名与扩展属性关联到一起,对于普通属性来说我们可以通过扩展对象的GetOwner方法得到一个扩展对象内部的对象实例,这里如果是一个扩展对象也就是说继承了ExtendObject的GetOwner方法取得的就是一个ExtendObject类型的对象,但是如果是一个AttachObject类型(还记得这个类型吧,它是继承自ExtendObject的)的对象的话GetOwner方法得到的就可能是任何对象(object),然后通过对象实例我们就可以取得扩展属性的值了,对于普通属性来说就通过了反射的方式来访问。

对于上面的动态性接口userInfo1类型是一个普通类型它没有继承任何其它类型,而在user1的Info属性就是它的一个扩展属性,如果Info属性没有在以前通过ExtendProperty.RegisterProperty方法注册过,系统则有默认生成一个Type为Object的扩展属性。不过在系统中注册扩展属性还是可以带好一些好处的,比如给扩展属性添加默认值、验证事件、属性值改变事件等。

   1:  private static ExtendProperty InfoProperty = 
   2:              ExtendProperty.RegisterProperty("Info", typeof(string), typeof(UserInfo),"you win");
   3:  InfoProperty.ValueChanging += new EventHandler<ExtendPropertyValueChangingArgs>                                              (InfoProperty_ValueChanging);
   4:  InfoProperty.ValueChanged += new EventHandler<ExtendPropertyValueChangedArgs>
                                              (InfoProperty_ValueChanged);

<!-- .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } -->

接下来看一个有意思的东西,属性继承:

什么是属性继承呢,简单的说就是类型A的某个属性,在类型B中也有相同名称的属性,且B中的属性要拥有A中属性的一些特性。我们来看看怎么实现属性继承:

   1:  private static ExtendProperty InfoProperty = 
   2:              ExtendProperty.RegisterProperty("Info", typeof(string), typeof(UserInfo),"you win");
   3:  InfoProperty.AddOwner(typeof(UserInfo1), "ha ha");

<!-- .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } -->

这里在扩展属性中UserInfo1类型就多出了一个Info属性且继承UserInfo类型中的Info属性。这里声明的结果是这两个类型都分别有不同的默认值,不过它们目前分享了两个事件(验证事件、属性值改变事件),如果在AddOwner方法中没有为类型UserInfo1添加默认值的话,那么在UserInfo1的对象实例第一次访问(取)Info这个扩展属性时,则取得的是”you win” 这个字符串,这就继承了类型UserInfo中的属性,前面说的用AddOwner方法添加默认值就相当于把类型UserInfo中的Info重写了。

为这达到这个目的其实只是在注册新属性(AddOwner方法)时以UserInfo1的类型 + 要继承的属性名 生成新的键,并且,指向原有的扩展属性(本质是两个对象共用一个属性).

其实这个概念和WPF中的附加属性有异曲同共。

希望我的文章可以扩展大家的思路并了解依赖属性与附加属性的原理 , 谢谢。

maxzhang1985@gmail.com 希望大家可以多多交流。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏PHP在线

php日常使用总结

Private(私有): 只能在这个当前类的内部读取、修改。 Protected(受保护):能够在这个类和类的子类中读取和修改。 在方法内部通过 $this...

37880
来自专栏枕边书

PHP用mb_string函数库处理与windows相关中文字符

昨天想批处理以前下载的一堆文件,把文件里的关键内容用正则匹配出来,集中处理。在操作文件时遇到一个问题,就是windows操作系统中的编码问题。 我们都知道win...

232100
来自专栏java一日一条

JVM内存的那些事

对于C语言开发的程序员来说,在内存管理方面,必须负责每一个对象的生命周期,从有到无。

7110
来自专栏不想当开发的产品不是好测试

优化testng报告

背景 搞过testng的同学都知道,testng自带的报告非常丑,而且有些字段的展示很不人性化,所以需要优化下报告 ? 解决方案 尝试过一下开源的jar包,如R...

23370
来自专栏java一日一条

Java编程常见问题汇总1

每天在写Java程序,其实里面有一些细节大家可能没怎么注意,这不,有人总结了一个我们编程中常见的问题。虽然一般没有什么大问题,但是最好别这样做。另外这里提到的很...

11620
来自专栏测试开发架构之路

堆和栈的区别

一、预备知识—程序的内存分配          一个由C/C++编译的程序占用的内存分为以下几个部分     1、栈区(stack)— 由编译器自动分配释放,存...

29180
来自专栏静晴轩

Url参数中出现+、空格、=、%、&、#等字符的解决办法

Url出现了有+,空格,/,?,%,#,&,=等特殊符号的时候,可能在服务器端无法获得正确的参数值,抑或是造成不能正常下载文件(作为Download Url时候...

42170
来自专栏积累沉淀

Java设计模式(八)----代理模式

代理描述 1.生活中: 代理就是一个人或者一个组织代表其他人去做一件事的现实生活中的。在一些情况下,一个客户不想或者不能够直接引用一个对...

21290
来自专栏C/C++基础

函数调用时堆栈的变化情况

函数的正常运行必然要利用堆栈,至少,函数的返回地址是保存在堆栈上的。函数一般要利用参数,而且内部也会用到局部变量,在对表达式进行求值时,编译器还会生成一些无名临...

8510
来自专栏积累沉淀

Java设计模式(八)----代理模式

代理模式 1.生活中: 代理就是一个人或者一个组织代表其他人去做一件事的现实生活中的。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对...

238100

扫码关注云+社区

领取腾讯云代金券