依赖属性之“风云再起”五
发布时间:2020-12-13 20:21:53 所属栏目:百科 来源:网络整理
导读:十二. 其他协助类测试代码 这里就简单写一下对DependencyObjectTypeTest的测试代码: 1: using System; 2: using System.Windows; 3: using NUnit.Framework; 4: 5: namespace TDDDependencyTest.System.Windows 6: { 7: [TestFixture] 8: public class Depe
十二. 其他协助类测试代码
这里就简单写一下对DependencyObjectTypeTest的测试代码:
1: using System; 2: using System.Windows; 3: using NUnit.Framework; 4:
5: namespace TDDDependencyTest.System.Windows 6: {
7: [TestFixture]
8: public class DependencyObjectTypeTest 9: {
10:
11: [Test]
12: void Accessors() 13: {
14: DependencyObjectType t = DependencyObjectType.FromSystemType(typeof(TestDepObj)); 15: Assert.AreEqual("TestDepObj",t.Name); 16: Assert.AreEqual(typeof(TestDepObj),t.SystemType); 17: Assert.AreEqual(typeof(DependencyObject),t.BaseType.SystemType); 18: }
19:
20: [Test]
21: void IsInstanceOfType() 22: {
23: DependencyObjectType t = DependencyObjectType.FromSystemType(typeof(TestDepObj)); 24: DependencyObjectType t2 = DependencyObjectType.FromSystemType(typeof(TestSubclass)); 25: Assert.IsTrue(t.IsInstanceOfType(new TestSubclass())); 26: Assert.IsTrue(t2.IsSubclassOf(t));
27: Assert.IsFalse(t.IsSubclassOf(t2));
28: }
29:
30: [Test]
31: void TestCache() 32: {
33: DependencyObjectType t = DependencyObjectType.FromSystemType(typeof(TestDepObj)); 34: DependencyObjectType t2 = DependencyObjectType.FromSystemType(typeof(TestDepObj)); 35: Assert.AreSame(t,t2);
36: }
37: }
38: }
由于它的功能比较简单,所以我们就不做过多介绍,大家想了解更多,可以参看代码。
十三. 其他协助类的实现代码
LocalValueEnumerator:手动实现一个IEnumerator来方便访问LocalValue
using System.Collections.Generic;
using System.Linq;
4: using System.Text; using System.Collections;
6:
7: namespace System.Windows 8: {
9: //手动实现一个IEnumerator来方便访问LocalValue 10: struct LocalValueEnumerator : IEnumerator 11: {
private IDictionaryEnumerator propertyEnumerator;
13: private Dictionary<DependencyProperty,object> properties; 14:
15: private int count; 16:
17: internal LocalValueEnumerator(Dictionary<DependencyProperty,255);">object> properties) 18: {
19: this.count = properties.Count; 20: this.properties = properties; 21: this.propertyEnumerator = properties.GetEnumerator(); 22: }
23:
24: int Count 25: {
26: get { return count; } 27: }
28:
29: //获取当前LocalValue 30: public LocalValueEntry Current 31: {
32: get
33: {
34: return new LocalValueEntry((DependencyProperty)propertyEnumerator.Key, 35: propertyEnumerator.Value);
36: }
37: }
38:
39: object IEnumerator.Current 40: {
41: get { this.Current; } 42: }
43:
44:
45: bool MoveNext() 46: {
47: return propertyEnumerator.MoveNext(); 48: }
49:
50: //重置propertyEnumerator 51: void Reset() 52: {
53: propertyEnumerator.Reset();
54: }
55:
56: static bool operator !=(LocalValueEnumerator obj1,LocalValueEnumerator obj2) 57: {
58: throw new NotImplementedException(); 59: }
60:
61: operator ==(LocalValueEnumerator obj1,LocalValueEnumerator obj2) 62: {
63: new NotImplementedException(); 64: }
65:
66: override bool Equals(object obj) 67: {
68: new NotImplementedException(); 69: }
70:
71: int GetHashCode() 72: {
73: new NotImplementedException(); 74: }
75: }
76:
77: //LocalValue实体类 78: struct LocalValueEntry 79: {
80: private DependencyProperty property; 81: object value; 82:
83: internal LocalValueEntry(DependencyProperty property,255);">value) 84: {
85: this.property = property; 86: this.value = value; 87: }
88:
89: public DependencyProperty Property 90: {
91: get { return property; } 92: }
93:
94: object Value 95: {
96: get { value; } 97: }
98:
99: operator !=(LocalValueEntry obj1,LocalValueEntry obj2) 100: {
101: new NotImplementedException(); 102: }
103:
104: operator ==(LocalValueEntry obj1,LocalValueEntry obj2) 105: {
106: new NotImplementedException(); 107: }
108:
109: object obj) 110: {
111: new NotImplementedException(); 112: }
113:
114: int GetHashCode() 115: {
116: new NotImplementedException(); 117: }
118: }
119: }
120:
DependencyPropertyChangedEventArgs:PropertyChangedCallback(DependencyObject d,DependencyPropertyChangedEventArgs e)的参数,它的第一个参数为该DependencyProperty、第二个参数为原来的值、第三个参数为改变了的值。
5:
6: namespace System.Windows 7: {
class DependencyPropertyChangedEventArgs
10: //第一个参数为该DependencyProperty、第二个参数为原来的值、第三个参数为新值 11: public DependencyPropertyChangedEventArgs(DependencyProperty property,255);">object oldValue,255);">object newValue) 12: {
13: this.Property = property; 14: this.OldValue = oldValue; 15: this.NewValue = newValue; 16: }
17:
18: //注意所有的属性只对外界开放只读操作 19: object NewValue 20: {
21: get;
22: private set; 23: }
24:
25: object OldValue 26: {
27: get;
28: private set; 29: }
30:
public DependencyProperty Property
33: get;
34: private set; 35: }
36:
37: object obj) 38: {
39: if (!(obj is DependencyPropertyChangedEventArgs)) 40: false; 41:
42: return Equals((DependencyPropertyChangedEventArgs)obj); 43: }
bool Equals(DependencyPropertyChangedEventArgs args)
return (Property == args.Property &&
48: NewValue == args.NewValue &&
49: OldValue == args.OldValue);
50: }
51:
52: operator !=(DependencyPropertyChangedEventArgs left,DependencyPropertyChangedEventArgs right) 53: {
54: new NotImplementedException(); 55: }
56:
57: operator ==(DependencyPropertyChangedEventArgs left,DependencyPropertyChangedEventArgs right) 58: {
59: new NotImplementedException(); 60: }
61:
62: int GetHashCode() 63: {
64: new NotImplementedException(); 65: }
66:
67: }
68: }
DependencyPropertyKey:构造函数传入该DependencyProperty,然后通过Type来OverrideMetadata,此类只是起到了封装作用。
1:
namespace System.Windows
3: {
4: //构造函数传入该DependencyProperty,然后通过Type来OverrideMetadata 5: sealed class DependencyPropertyKey 6: {
7: internal DependencyPropertyKey (DependencyProperty dependencyProperty) 8: {
9: this.dependencyProperty = dependencyProperty; 10: }
11:
private DependencyProperty dependencyProperty;
public DependencyProperty DependencyProperty {
14: get { return dependencyProperty; } 15: }
void OverrideMetadata(Type forType,PropertyMetadata typeMetadata)
19: dependencyProperty.OverrideMetadata (forType,typeMetadata,255);">this);
20: }
21: }
22: }
DependencyObjectType:用静态Dictionary<Type,DependencyObjectType>来存储DependencyObjectType,主要有FromSystemType、 IsInstanceOfType和IsSubclassOf三个功能。
class DependencyObjectType
//键为Type(即OwnerType),值为DependencyObjectType(即ID和systemType)的键值对
static Dictionary<Type,DependencyObjectType> typeMap = new Dictionary<Type,DependencyObjectType>(); int current_id;
13:
14: int id; private Type systemType;
//构造函数私有,在FromSystemType里进行构造,初始化id和systemType
private DependencyObjectType(int id,Type systemType) 19: {
this.id = id;
this.systemType = systemType;
//基类型的DependencyObjectType
public DependencyObjectType BaseType
27: get { return DependencyObjectType.FromSystemType(systemType.BaseType); } int Id
32: get { return id; } 33: }
34:
35: string Name 36: {
37: get { return systemType.Name; } 38: }
39:
40: public Type SystemType 41: {
42: get { return systemType; } //用静态Dictionary<Type,DependencyObjectType>来存储DependencyObjectType
46: static DependencyObjectType FromSystemType(Type systemType) 47: {
48: if (typeMap.ContainsKey(systemType)) 49: return typeMap[systemType]; 50:
51: DependencyObjectType dot;
52:
53: typeMap[systemType] = dot = new DependencyObjectType(current_id++,systemType); 54:
55: return dot; 56: }
57:
58: //是否是该DependencyObject的子类实例 59: bool IsInstanceOfType(DependencyObject d) 60: {
61: return systemType.IsInstanceOfType(d); 62: }
63:
64: //该DependencyObjectType是否是传入DependencyObjectType的子实例 65: bool IsSubclassOf(DependencyObjectType dependencyObjectType) 66: {
67: return systemType.IsSubclassOf(dependencyObjectType.SystemType); 68: }
69:
70: int GetHashCode() 71: {
72: new NotImplementedException(); 73: }
74: }
75: }
76:
十四. 回归并统计覆盖率
在上面的开发过程中,我们会不断的运行和查看代码通过情况,最后我们也来看一下测试用例的总体通过情况,其实在前面已经运行过很多次了,因为每个功能都要经过”测试代码-功能代码-测试-重构“等步骤。
最后也看一下代码测试覆盖率,代码测试覆盖率对一个系统或者产品来说是一个比较重要的质量指标,可以通过它看出系统的稳定性和可控性。一般在项目的开发中,我们都会以85%~90%的测试代码覆盖率作为达标的参考标准。
由于MONO本身对依赖属性没有那么健全,我们也没有写那么详细的测试代码,中间直接就实现了一些功能,严格地说,所以本文并没有完全遵从正规的测试驱动开发流程。
十五. 简单验证依赖属性系统
其实通过上面的测试用例,基本就用不着再单独测试了,但鉴于覆盖率比较低的问题,所以最后我们还是来测试一下刚才构建的依赖属性系统:
class Program
2: {
3: void Main(string[] args) 4: {
5: SimpleDPClass sDPClass = new SimpleDPClass(); 6: sDPClass.SimpleDP = 8;
7: Console.ReadLine();
8: }
9: }
11: class SimpleDPClass : DependencyObject 12: {
13: readonly DependencyProperty SimpleDPProperty = 14: DependencyProperty.Register("SimpleDP",255);">typeof(double),255);">typeof(SimpleDPClass), new PropertyMetadata((double)0.0, 16:
17: new PropertyChangedCallback(OnValueChanged), 18: new CoerceValueCallback(CoerceValue)), 19: new ValidateValueCallback(IsValidValue)); 20:
21: double SimpleDP 22: {
23: get { return (double)GetValue(SimpleDPProperty); } 24: set { SetValue(SimpleDPProperty,255);">value); }
25: }
26:
27: void OnValueChanged(DependencyObject d,DependencyPropertyChangedEventArgs e) 28: {
29: Console.WriteLine("当值改变时,我们可以做的一些操作,具体可以在这里定义: {0}",e.NewValue); 30: }
31:
32: object CoerceValue(DependencyObject d,255);">value) 33: {
34: Console.WriteLine("对值进行限定,强制值: {0}",255);">value); value;
36: }
37:
38: bool IsValidValue(value) 39: {
40: Console.WriteLine("验证值是否通过,如果返回True表示验证通过,否则会以异常的形式暴露: {0}",255);">value); 41: true; 42: }
44: }
测试结果:
到处为止,我们这篇文章也宣告结束。
十六. 本文总结
本篇承接上一篇
WPF基础到企业应用系列7――深入剖析依赖属性的 写作风格,对上篇模拟一个WPF依赖属性的实现重现演绎了一遍,上篇是根据微软WPF的BCL源码剖析的,所以这篇我们就详细的研究一下.NET的跨平台 版本MONO关于依赖属性系统的实现。在这篇文章中,我只是起到了剖析源码的作用,就像研究微软的BCL一样,不过MONO的代码远没有微软的BCL那么 庞大,所以研究和复原起来不是很吃力。如果大家还想继续深入,可以去下载相关源码,也希望大家和我一起交流探讨。
十七. 相关代码下载
在文章的最后,和往常一样,我们提供代码的下载,再次温馨提示:这几篇文章最重要的就是下载代码来细细研究,代码里面也添加了比较详细的注释,如果大家有什么问题,也可以直接和我联系,如果有不正确的地方也希望多多海涵并能给我及时反馈,我将感激不尽!
上图就是整个代码包的结构图,下载链接: DependencySystem.rar 十八.系列进度
云计算专区(
http://home.cnblogs.com/group/CloudComputing/),如果大家有什么云计算相关的疑问或话题也可以在里面进行探讨。由于圣殿骑士以后会定格和专注于这几个方向,所以很希望同大家一起交流和进步!
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |