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

时间:2022-06-09
本文章向大家介绍动手实现扩展属性为对象动态添加获取数据(续),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

上一篇文章中我们了解了扩展属性的原理和结构,其实其内部结构与思想都与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 希望大家可以多多交流。