博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
依赖属性之“风云再起”五
阅读量:7038 次
发布时间:2019-06-28

本文共 13453 字,大约阅读时间需要 44 分钟。

十二. 其他协助类测试代码

这里就简单写一下对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:         public 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:         public 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:         public 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
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.Collections;
6: 
7: namespace System.Windows
8: {
9:     //手动实现一个IEnumerator来方便访问LocalValue
10:     public struct LocalValueEnumerator : IEnumerator
11:     {
12:         private IDictionaryEnumerator propertyEnumerator;
13:         private Dictionary
properties;
14: 
15:         private int count;
16: 
17:         internal LocalValueEnumerator(Dictionary
properties)
18:         {
19:             this.count = properties.Count;
20:             this.properties = properties;
21:             this.propertyEnumerator = properties.GetEnumerator();
22:         }
23: 
24:         public 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 { return this.Current; }
42:         }
43: 
44: 
45:         public bool MoveNext()
46:         {
47:             return propertyEnumerator.MoveNext();
48:         }
49: 
50:         //重置propertyEnumerator
51:         public void Reset()
52:         {
53:             propertyEnumerator.Reset();
54:         }
55: 
56:         public static bool operator !=(LocalValueEnumerator obj1, LocalValueEnumerator obj2)
57:         {
58:             throw new NotImplementedException();
59:         }
60: 
61:         public static bool operator ==(LocalValueEnumerator obj1, LocalValueEnumerator obj2)
62:         {
63:             throw new NotImplementedException();
64:         }
65: 
66:         public override bool Equals(object obj)
67:         {
68:             throw new NotImplementedException();
69:         }
70: 
71:         public override int GetHashCode()
72:         {
73:             throw new NotImplementedException();
74:         }
75:     }
76: 
77:     //LocalValue实体类
78:     public struct LocalValueEntry
79:     {
80:         private DependencyProperty property;
81:         private object value;
82: 
83:         internal LocalValueEntry(DependencyProperty property, object value)
84:         {
85:             this.property = property;
86:             this.value = value;
87:         }
88: 
89:         public DependencyProperty Property
90:         {
91:             get { return property; }
92:         }
93: 
94:         public object Value
95:         {
96:             get { return value; }
97:         }
98: 
99:         public static bool operator !=(LocalValueEntry obj1, LocalValueEntry obj2)
100:         {
101:             throw new NotImplementedException();
102:         }
103: 
104:         public static bool operator ==(LocalValueEntry obj1, LocalValueEntry obj2)
105:         {
106:             throw new NotImplementedException();
107:         }
108: 
109:         public override bool Equals(object obj)
110:         {
111:             throw new NotImplementedException();
112:         }
113: 
114:         public override int GetHashCode()
115:         {
116:             throw new NotImplementedException();
117:         }
118:     }
119: }
120: 
   DependencyPropertyChangedEventArgs:PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)的参数,它的第一个参数为该DependencyProperty、第二个参数为原来的值、第三个参数为改变了的值。
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: 
6: namespace System.Windows
7: {
8:     public class DependencyPropertyChangedEventArgs
9:     {
10:         //第一个参数为该DependencyProperty、第二个参数为原来的值、第三个参数为新值
11:         public DependencyPropertyChangedEventArgs(DependencyProperty property, object oldValue, object newValue)
12:         {
13:             this.Property = property;
14:             this.OldValue = oldValue;
15:             this.NewValue = newValue;
16:         }
17: 
18:         //注意所有的属性只对外界开放只读操作
19:         public object NewValue
20:         {
21:             get;
22:             private set;
23:         }
24: 
25:         public object OldValue
26:         {
27:             get;
28:             private set;
29:         }
30: 
31:         public DependencyProperty Property
32:         {
33:             get;
34:             private set;
35:         }
36: 
37:         public override bool Equals(object obj)
38:         {
39:             if (!(obj is DependencyPropertyChangedEventArgs))
40:                 return false;
41: 
42:             return Equals((DependencyPropertyChangedEventArgs)obj);
43:         }
44: 
45:         public bool Equals(DependencyPropertyChangedEventArgs args)
46:         {
47:             return (Property == args.Property &&
48:                 NewValue == args.NewValue &&
49:                 OldValue == args.OldValue);
50:         }
51: 
52:         public static bool operator !=(DependencyPropertyChangedEventArgs left, DependencyPropertyChangedEventArgs right)
53:         {
54:             throw new NotImplementedException();
55:         }
56: 
57:         public static bool operator ==(DependencyPropertyChangedEventArgs left, DependencyPropertyChangedEventArgs right)
58:         {
59:             throw new NotImplementedException();
60:         }
61: 
62:         public override int GetHashCode()
63:         {
64:             throw new NotImplementedException();
65:         }
66: 
67:     }
68: }
DependencyPropertyKey:构造函数传入该DependencyProperty,然后通过Type来OverrideMetadata,此类只是起到了封装作用。
1: 
2: namespace System.Windows
3: {
4:     //构造函数传入该DependencyProperty,然后通过Type来OverrideMetadata
5:     public sealed class DependencyPropertyKey
6:     {
7:         internal DependencyPropertyKey (DependencyProperty dependencyProperty)
8:         {
9:             this.dependencyProperty = dependencyProperty;
10:         }
11: 
12:         private DependencyProperty dependencyProperty;
13:         public DependencyProperty DependencyProperty {
14:             get { return dependencyProperty; }
15:         }
16: 
17:         public void OverrideMetadata(Type forType, PropertyMetadata typeMetadata)
18:         {
19:             dependencyProperty.OverrideMetadata (forType, typeMetadata, this);
20:         }
21:     }
22: }
  DependencyObjectType:用静态Dictionary<Type, DependencyObjectType>来存储DependencyObjectType,主要有FromSystemType、 IsInstanceOfType和IsSubclassOf三个功能。
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: 
6: namespace System.Windows
7: {
8:     public class DependencyObjectType
9:     {
10:         //键为Type(即OwnerType),值为DependencyObjectType(即ID和systemType)的键值对
11:         private static Dictionary
typeMap = new Dictionary
();
12:         private static int current_id;
13: 
14:         private int id;
15:         private Type systemType;
16: 
17:         //构造函数私有,在FromSystemType里进行构造,初始化id和systemType
18:         private DependencyObjectType(int id, Type systemType)
19:         {
20:             this.id = id;
21:             this.systemType = systemType;
22:         }
23: 
24:         //基类型的DependencyObjectType
25:         public DependencyObjectType BaseType
26:         {
27:             get { return DependencyObjectType.FromSystemType(systemType.BaseType); }
28:         }
29: 
30:         public int Id
31:         {
32:             get { return id; }
33:         }
34: 
35:         public string Name
36:         {
37:             get { return systemType.Name; }
38:         }
39: 
40:         public Type SystemType
41:         {
42:             get { return systemType; }
43:         }
44: 
45:         //用静态Dictionary
来存储DependencyObjectType
46:         public 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:         public bool IsInstanceOfType(DependencyObject d)
60:         {
61:             return systemType.IsInstanceOfType(d);
62:         }
63: 
64:         //该DependencyObjectType是否是传入DependencyObjectType的子实例
65:         public bool IsSubclassOf(DependencyObjectType dependencyObjectType)
66:         {
67:             return systemType.IsSubclassOf(dependencyObjectType.SystemType);
68:         }
69: 
70:         public override int GetHashCode()
71:         {
72:             throw new NotImplementedException();
73:         }
74:     }
75: }
76: 

十四. 回归并统计覆盖率

  在上面的开发过程中,我们会不断的运行和查看代码通过情况,最后我们也来看一下测试用例的总体通过情况,其实在前面已经运行过很多次了,因为每个功能都要经过”测试代码-功能代码-测试-重构“等步骤。
  最后也看一下代码测试覆盖率,代码测试覆盖率对一个系统或者产品来说是一个比较重要的质量指标,可以通过它看出系统的稳定性和可控性。一般在项目的开发中,我们都会以85%~90%的测试代码覆盖率作为达标的参考标准。
  由于MONO本身对依赖属性没有那么健全,我们也没有写那么详细的测试代码,中间直接就实现了一些功能,严格地说,所以本文并没有完全遵从正规的测试驱动开发流程。

十五. 简单验证依赖属性系统

其实通过上面的测试用例,基本就用不着再单独测试了,但鉴于覆盖率比较低的问题,所以最后我们还是来测试一下刚才构建的依赖属性系统:
1: class Program
2: {
3:     static void Main(string[] args)
4:     {
5:         SimpleDPClass sDPClass = new SimpleDPClass();
6:         sDPClass.SimpleDP = 8;
7:         Console.ReadLine();
8:     }
9: }
10: 
11: public class SimpleDPClass : DependencyObject
12: {
13:     public static readonly DependencyProperty SimpleDPProperty =
14:         DependencyProperty.Register("SimpleDP", typeof(double), typeof(SimpleDPClass),
15:             new PropertyMetadata((double)0.0,
16:
17:                 new PropertyChangedCallback(OnValueChanged),
18:                 new CoerceValueCallback(CoerceValue)),
19:                 new ValidateValueCallback(IsValidValue));
20: 
21:     public double SimpleDP
22:     {
23:         get { return (double)GetValue(SimpleDPProperty); }
24:         set { SetValue(SimpleDPProperty, value); }
25:     }
26: 
27:     private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
28:     {
29:         Console.WriteLine("当值改变时,我们可以做的一些操作,具体可以在这里定义: {0}", e.NewValue);
30:     }
31: 
32:     private static object CoerceValue(DependencyObject d, object value)
33:     {
34:         Console.WriteLine("对值进行限定,强制值: {0}", value);
35:         return value;
36:     }
37: 
38:     private static bool IsValidValue(object value)
39:     {
40:         Console.WriteLine("验证值是否通过,如果返回True表示验证通过,否则会以异常的形式暴露: {0}", value);
41:         return true;
42:     }
43: 
44: }
测试结果:
到处为止,我们这篇文章也宣告结束。

十六. 本文总结

  本篇承接上一篇 的 写作风格,对上篇模拟一个WPF依赖属性的实现重现演绎了一遍,上篇是根据微软WPF的BCL源码剖析的,所以这篇我们就详细的研究一下.NET的跨平台 版本MONO关于依赖属性系统的实现。在这篇文章中,我只是起到了剖析源码的作用,就像研究微软的BCL一样,不过MONO的代码远没有微软的BCL那么 庞大,所以研究和复原起来不是很吃力。如果大家还想继续深入,可以去下载相关源码,也希望大家和我一起交流探讨。

十七. 相关代码下载

  在文章的最后,和往常一样,我们提供代码的下载,再次温馨提示:这几篇文章最重要的就是下载代码来细细研究,代码里面也添加了比较详细的注释,如果大家有什么问题,也可以直接和我联系,如果有不正确的地方也希望多多海涵并能给我及时反馈,我将感激不尽!
   
上图就是整个代码包的结构图,下载链接:

十八.系列进度

前篇
            
· 9. WPF 基础到企业应用系列9——深入剖析WPF事件机制 (核心篇)     
·10. WPF 基础到企业应用系列10——WPF事件机制之“刨根问底”
·11. WPF 基础到企业应用系列11——深入剖析WPF命令机制 (核心篇)  
·12. WPF 基础到企业应用系列12——WPF命令之“庖丁解牛”
·13. WPF 基础到企业应用系列13——WPF Binding全接触 (核心篇)   
·14. WPF 基础到企业应用系列14——WPF Binding之“面面俱到”
中篇
· 1. 资源、样式、模板
· 2. 尺寸缩放、定位与变换元素
· 3. WPF控件分类介绍与使用技巧
· 4. 用户控件和自定义控件开发
· 5. 多语言、皮肤和主题
· 6. 2D图形
· 7. 3D图形
· 8. 动画(几种动画的应用)
· 9. 音频、视频、语音
· 10. 文档、打印、报表
后篇
· 1. Win32、Windows Form以及ActiveX之间的互用性
· 2. 构建并部署应用程序(ClickOnce部署、微软setup /InstallShield+自动更新组件)
· 3. MVC、MVP、MVVM全解析
· 4. WPF的模式讲解及实例(MVC Demo)
· 5. WPF的模式讲解及实例(MVP Demo)
· 6. WPF的模式讲解及实例(MVVM Demo)
· 7. 性能优化(WPF项目的瓶颈)
· 8.一个完整WPF项目(普通架构版)
· 9. 一个完整WPF项目(MVVM架构版)
· 10. WPF 4.0新功能
),如果大家有什么云计算相关的疑问或话题也可以在里面进行探讨。由于圣殿骑士以后会定格和专注于这几个方向,所以很希望同大家一起交流和进步!
本文转自KnightsWarrior51CTO博客,原文链接:http://blog.51cto.com/knightswarrior/405236
 ,如需转载请自行联系原作者
你可能感兴趣的文章
《Dreamweaver CS6完美网页制作——基础、实例与技巧从入门到精通》——第2章 网页色彩知识2.1 网页配色基础...
查看>>
物联网设备安全1.6 小结
查看>>
细数二十世纪最伟大的十大算法
查看>>
《机器学习与数据科学(基于R的统计学习方法)》——2.10 SQL数据库
查看>>
MySQL 中你应该使用什么数据类型表示时间?
查看>>
《Visual Basic 2012入门经典》----1.6 设计界面
查看>>
《易学C++(第2版)》——1.3 选好一种语言
查看>>
Java8中CAS的增强
查看>>
基本线程同步(四)在同步代码中使用条件
查看>>
高管必备思维:区分2类问题和4类可视化方法
查看>>
《C++ 黑客编程揭秘与防范(第2版)》——第6章 加密与解密
查看>>
《Visual C++ 开发从入门到精通》——2.4 输入/输出基础
查看>>
地平线谭洪贺:AI芯片怎么降功耗?从ISSCC2017说起
查看>>
《树莓派用户指南(第3版)》——第1篇 主板 第1章 初识树莓派 1.1 主板简介...
查看>>
MySQL · myrocks · fast data load
查看>>
使用 Linux/Unix 进行文本处理
查看>>
【直播系列之一】1篇文章看懂峰值带宽、流量、转码、连麦、截图五大直播计费方式...
查看>>
PostgreSQL 巧妙的数据采样方法
查看>>
[LeetCode]--232. Implement Queue using Stacks
查看>>
浅谈Android应用保护(一):Android应用逆向的基本方法
查看>>