在实现扩展属性时我也参考了依赖属性的源码,它的设计思想的确很“先进”。
1.先来看看扩展属性的使用方式:
1: private static ExtendProperty InfoProperty = 2: ExtendProperty.RegisterProperty("Info", typeof(string), typeof(UserInfo),"you win"); 3: var user = new UserInfo() { Age=21, Name="maxzhang" }; 4: 5: user.SetValue(InfoProperty, "hello"); 6: string rrr = (string)user.GetValue(InfoProperty);
是不是看着特别像依赖属性呢,往下面看:
1: dynamic userDynamic = user.AsDynamic(); 2: rrr= userDynamic.Info; 3: userDynamic.Info = "1"; 4: userDynamic.Age = 50; 5: rrr = userDynamic.Info;
我为扩展属性添加了动态性使对象属性的创建和访问更加方便,这里如果Info属性在前面没有用RegisterProperty方法定义过它会自动生成一个扩展属性且添加属性值.如果访问了它的普通属性属性也是正常使用的。以上两个例子中
UserInfo类的定义是 public class UserInfo : ExtendObject { public string Name { set; get; } public int Age { set; get; }},你可能会问这不是和依赖属性一样吗?只是把继承DependencyObject换成了继承你自己写的ExtendObject 了。是的这样看是差不多的,不过以上的情况还是有一个好处的就是我可以在任何项目里引用它。
如果遇到了不能继承的情况呢,其实这种情况有很多。接…
public class UserInfo1 { public string Name{set;get;} } 这个类不继承任何类。
解决它这里引入了新的扩展类型AttachObject :
1: AttachObject user1Aobj = new AttachObject(user1); 2: var dyuser = user1Aobj.ToDynamicAttachObject(); 3: //var dyuser = user1.ToDynamicAttachObject(); 4: dyuser.Memo = "haha my name i's maxzhang......"; 5: rrr = dyuser.Memo;
其实AttachObject 类型也是一个ExtendObject 可以把它看成是一个ExtendObject 的装饰。
2.下面我们来看看这些都是怎么实现的
(1).ExtendProperty
与依赖属性类似,在ExtendProperty类中用了一个Dictionary<int,ExtendProperty>来存储系统中要用到的扩展属性,这样实现也达到了节省内存资源的目地。且这个类的构造器是一个private的,这样也就实现了一个单例模式,只有在RegisterProperty方法才能创造出一个ExtendProperty来.
RegisterPropertypublic static ExtendProperty RegisterProperty(string propertyName, Type propertyType, Type ownerType,object defaultValue)
{
var property = new ExtendProperty(propertyName, propertyType,ownerType);
property.OverrideDefaultValue(ownerType, defaultValue);
ExtendPropertysProvider.Set(property.GetHashCode(), property);
return property;
}
用GetHashCode来标示我们这个属性的唯一性,这里我重写了这个函数它的值是this.ownerType.GetHashCode()^this.propertyName.GetHashCode(),也就是说用注册这个属性的类型和属性的名称确定了这个扩展属性。我们看到OverrideDefaultValue这个方法它是用来重写属性的默认值的,在这个系统中如果某个对象的扩展属性没有赋过值或说没有改变过,那么它应该在访问这个属性的时候取得一个默认值而且这个默认值应该是所有相同注册类型的对象共有的,而在用普通属性存储的对象中我们实例化对象后会在每一个对象中保存相应的默认值,这样无疑是浪费了内存。而且OverrideDefaultValue与AddOwner方法一起使用可以达到属性继承的目的。我们来看看AddOwner方法的实现:AddOwnerpublic ExtendProperty AddOwner(Type ownerType,object defaultValue)
{
int newOwnerHash = ownerType.GetHashCode() ^ this.PropertyName.GetHashCode();
if(defaultValue!=null)
this.OverrideDefaultValue(ownerType, defaultValue);
ExtendPropertysProvider.Set(newOwnerHash, this);
return this;
}
使用AddOwner方法我们就在原有的扩展属性上添加了一个指向它的引用从而达到继承的目地,怎么重写属性默认值呢?其实很简单默认值在扩展属性中保存在一个<type,object>的字典中通过不同的类型我们就可以访问不同类型的相同属性的默认值了。 (2).ExtendObject
这里ExtendObject就没什么好说的了,原理就是其内部有一个Dictionary<int, object> propertyValues 存储着不同对象的值,用自身的GetHashCode ^ 扩展属性的HashCode 确定值的唯一性。
ExtendObject的源码,呵呵 public class ExtendObject
{
protected Dictionary<int, object> propertyValues = new Dictionary<int, object>();
private Type OwnerType = null;
public ExtendObject()
{
OwnerType = this.GetType();
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public virtual object GetOwner()
{
return this;
}
protected void AttachOwner(Type ownerType)
{
this.OwnerType = ownerType;
}
public bool IsExtendProperty(string propertyName)
{
return !OwnerType.GetProperties().Any(p => p.Name == propertyName); ;
}
protected ExtendProperty GetProperty(string name)
{
int propertyKey = OwnerType.GetHashCode() ^ name.GetHashCode();
var property = ExtendPropertysProvider.Get(propertyKey);
return property;
}
public object GetValue(ExtendProperty property)
{
int propertyHash = property.GetHashCode();
int key = this.GetHashCode() ^ propertyHash;
object result = null;
if (!propertyValues.TryGetValue(key, out result))
{
result = property.GetDefaultValue(this.OwnerType);
}
return result;
}
public bool ClearValue(ExtendProperty property)
{
bool result = false;
int propertyHash = property.GetHashCode();
int key = this.GetHashCode() ^ propertyHash;
if (propertyValues.Keys.Any(k => k == key))
{
propertyValues.Remove(key);
result = true;
}
return result;
}
public void SetValue(ExtendProperty property, object value)
{
var changedItemArgs = new ExtendPropertyValueChangedArgs();
int propertyHash = property.GetHashCode();
int key = this.GetHashCode() ^ propertyHash;
if (propertyValues.Keys.Any(k => k == key))
{
changedItemArgs.OldValue = propertyValues[key];
propertyValues[key] = value;
}
else
{
changedItemArgs.OldValue = null;
propertyValues.Add(key, value);
}
changedItemArgs.Item = GetOwner();
changedItemArgs.PropertyType = property.PropertyType;
changedItemArgs.PropertyName = property.PropertyName;
changedItemArgs.NewValue = value;
property.OnValueChanged(changedItemArgs);
}
public bool ClearValue(string propertyName)
{
var property = this.GetProperty(propertyName);
if (property != null)
return this.ClearValue(property);
return false;
}
public object GetValue(string propertyName)
{
var property = this.GetProperty(propertyName);
if (property != null)
return this.GetValue(property);
return null;
}
public void SetValue(string propertyName, object value)
{
var property = this.GetProperty(propertyName);
if (property != null)
{
this.SetValue(property, value);
}
else
{
var newProperty = ExtendProperty.RegisterProperty(propertyName, typeof(object), OwnerType);
this.SetValue(newProperty, value);
}
}
public ExtendDynamicObject AsDynamic()
{
return new ExtendDynamicObject(this);
}
}
不过这里还是有一个小小的技巧的就是OwnerType这个属性和AttachOwner方法,默认的OwnerType属性的值是扩展对象本身的Type,但是通过 AttachOwner方法我们可以改变这个属性从而达到将不继承自ExtendObject类型的对象装饰成ExtendObject
对象的目地。
(3).也就是AttachObject
AttachObject类通过调用AttachOwner方法使用了这个技巧,同时把同样为ExtendObject的对象的属性统统都Copy过来.
AttachObjectpublic class AttachObject : ExtendObject
{
private object owner;
public AttachObject(object obj)
: base()
{
owner = obj;
if (owner is ExtendObject)
{
Type ownerType = typeof(ExtendObject);
FieldInfo fInfo = ownerType.GetField("propertyValues", BindingFlags.Default | BindingFlags.NonPublic | BindingFlags.Instance);
var ownerValues = fInfo.GetValue(owner) as Dictionary<int, object>;
foreach (var v in ownerValues)
this.propertyValues.Add(v.Key, v.Value);
}
this.AttachOwner(owner.GetType());
}
public override object GetOwner()
{
return owner;
}
public override int GetHashCode()
{
return owner.GetHashCode();
}
}
今天到这里