漫谈Visual C#的组件设计方法

2016-02-19 15:08 1 1 收藏

今天图老师小编给大家介绍下漫谈Visual C#的组件设计方法,平时喜欢漫谈Visual C#的组件设计方法的朋友赶紧收藏起来吧!记得点赞哦~

【 tulaoshi.com - 编程语言 】

  Properties

  在C#中为类预定义属性是件再简单不过的事,见程序1。

  程序1

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)
using System;namespace PropertiesDemo{ public class MyData {  ............... } public class Class1 {  private MyData _data;  public MyData Data  {   get { return _data; }  }  public Class1()  {   _data = new MyData();  } }}

  这是相当常见的属性预定义方式,同时也是个可正常运行的程序,不过其中隐含着一个设计上的问题,那就是创建MyData对象的时机。按照程序2-1的手法,当Class1对象被创建之初,其内的_data对象也随着被创建起来,这造成了Class1对象于创建初期就付出了一个MyData对象的内存成本,这对简单的类来说或如牛毛,但倘若Class1对象中拥有一群这类属性呢?为了解决这类问题,.NET Framework中大量使用Lazy-Allocate(缓分配)技术,见程序2。

  程序2 Lazy-Allocate范例

public class Class1{ private MyData _data; public MyData Data {  get  {   if(_data == null)    data = new MyData();   return _data;  } } public Class1() { }}

  Lazy-Allocate的设计概念很简单,就是未使用前不预付成本。相对于程序2-1所使用的Pre-Allocate(预分配)概念,程序2-2采取以时间换取空间的策略,付出存取判断式的代价来减轻空间浪费的情况。当然,Pre-Allocate也不是一无是处,不须预判断的快速存取特色适用于用户必然会存取的属性,但在一些特定的属性上,例如ASP.NET中常见的Style属性就不适合使用Pre-Allocate技巧,因为用户不一定会使用该属性,于此情况下,Lazy-Allocate模式说可以让对象省下一些内存成本。

  Event

  事件处理是组件设计中相当重要的一环,在C#中事件与delegate是紧密相关的,程序3是一个简单的事件范例。

  程序3 简单的事件范例

using System;namespace EventDemo{ public delegate void ProcessHandler(object sender); public class Class1 {  private event ProcessHandler _processHandler = null;  public event ProcessHandler ProcessStart  {   add   {    _processHandler += value;   }   remove   {    _processHandler -= value;   }  }  public void Process()  {   _processHandler(this);   for(int i = 0; i  10; i++)    i = i+1;  }  public Class1()  {} }}

  C#之中delegate扮演着函数指针的角色,用户可以将某个函数加入一个delegate之中,而一个delegate允许用户加入一个以上的函数,当调用此delegate时就等同于调用其内所含的所有函数。不过程序2-3的设计手法潜藏着一个问题,就是当事件数众多时,对象就必须付出相应数量的delegate变量,如程序4所示。

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

  程序4 传统事件设计

private event ProcessHandler _processStart = null;private event ProcessHandler _processEnd = null;private event ProcessHandler _processStep = null;

  不管用户是否用到了这些事件,当对象被创建起来时就得付出这些成本,这在窗口应用程序上更显得可怕,因为Windows Message(窗口消息)的数量以千为单位,假如一个简单的窗口程序就必须付出相对于Windows Message数量的变量成本,这样一来对象岂不成了庞然大物了。针对这个问题,.NET Framework采取了与Lazy-Allocate类似的方式来处理,见程序5。

  程序5 新事件设计模式

public class Class1{ private Hashtable _eventList = new Hashtable(); private static object _processStart = new object(); private static object _processEnd = new object(); public event ProcessHandler ProcessStart {  add  {   _eventList.Add(_processStart,value);  }  remove  {   _eventList.Remove(_processStart);  } } public event ProcessHandler ProcessEnd {  add  {   _eventList.Add(_processEnd,value);  }  remove  {   _eventList.Remove(_processEnd);  } } public void Process() {  ProcessHandler start = (ProcessHandler)_eventList[_processStart];  ProcessHandler end = (ProcessHandler)_eventList[_processEnd];  if(start != null) start(this);   for(int i = 0; i  10; i++)    i = i+1;    if(end != null)     end(this); }

  程序中声明了一个Hashtable类型的对象:_eventList,每一个Class1类的实体都拥有这个对象,另外还声明了两个object类型的对象:_processStart、_processEnd,注意!这两个对象是static(静态)类型,也就是说,不管有多少个对象实体,都只须花费两个object的空间。那这与2-4的范例做法有何不同呢?答案是对象所占的内存大小不同,当用户创建一个对象实体之后,此对象占用了一个Hashtable对象的内存空间,在用户设定了ProcessStart事件时,此对象随之占用了一个Hashtable元素的内存空间,若用户未设定事件,那么此元素的内存空间就不会被占用,相较于2-4范例的预付行为,此方式可以省下不必要付出的内存成本。再详细点说,假设Class1拥有1000个事件,那么程序2-4的做法在对象创建初期就会占用1000个event变量的内存空间,而程序2-5则要付出一个Hashtable对象及1000个static变量的代价,当用户创建了第二个对象时,程序2-4要再次占用了1000个event变量的代价,但程序5只须占用一个Hashtable对象的代价,优劣立见不是吗?很幸运,这种设计概念在.NET Framework中已提供了基础建设,设计人员只要套用即可,见程序6。

  程序6 .NET Framework内建的事件支持

public class Component1:Component{ private static object _processStart = new object(); public event EventHandler ProcessStart {  add  {   Events.AddHandler(_processStart,value);  }  remove  {   Events.RemoveHandler(_processStart,value);  } } public void Process() {  EventHandler handler = (EventHandler)Events[_processStart];  if(handler != null)   handler(this,null); }}

  只要继承自Component类或其子类就可使用这种方式来处理事件。

  Static Helper Object

  C#是个纯OOP的语言,这代表着它不允许设计人员声明全局性的函数或是变量,它提倡以静态函数与静态变量来取代原本须要使用全局性函数及变量的地方,由于静态函数与静态变量都要声明于类内,这个限制形成群集的效应,同时引出了另一种类型的运用:Static Helper Object,见程序7。

  程序7 Static Helper Object范例

public sealed class DomainHelper{ public static string GetCurrentDomainDir() {  return AppDomain.CurrentDomain.BaseDirectory; } private DomainHelper() {}}............MessageBox.Show(DomainHelper.GetCurrentDomainDir());

  DomainHelper是一个不允许继承且具备私有构造函数的类,这代表着设计人员不可能创建或是继承此类,DomainHelper提供了GetCurrentDomainDir静态函数,用来返回目前Application Domain所在的路径,这比起原来调用AppDomain. GetCurrentDomain. BaseDirectory函数来取得同样结果的方式简短了许多。Helper Object的中心概念就是将常用的辅助型函数包装成静态函数,设计人员就无须一再重复地撰写这些程序代码,组件设计技术与Helper Object息息相关,读者们会在后面的章节中看到更多这类型的例子。

来源:https://www.tulaoshi.com/n/20160219/1608973.html

延伸阅读
标签: vb
以前在用Delphi写程序的时候,总不喜欢在窗体上排放很多组件,这一方面有点不美观,并且在调试程序时候,也不是十分方便。通常在写程序的时候,当要用到某些组件,采用的方法一般都是动态创建,用完以后就释放掉。Visual C#在程序运行的时候也可以动态创建组件,下面就结合一个程序例子来具体介绍如何用Visual C#动态生成组件。首先让我们了...
推荐: Visual C# 轻松入门全攻略 匿名方法基础 匿名方法是C#2.0的一个新的语言特性。本文的主要内容是提供给读者关于匿名方法的内部实现和工作方式的一个更好的理解。本文无意于成为匿名方法的完全语言特性参考。 匿名方法允许我们定义委托对象可以接受的代码块。这个功能省去我们创建委托时想要传递给一个...
获取文件的版本信息: FileVersionInfo myFileVersionInfo1 = FileVersionInfo.GetVersionInfo("D:\\TEST.DLL"); textBox1.Text="版本号: " + myFileVersionInfo1.FileVersion; 更改文件属性,删除只读文件: 下例欲将E:\test.txt文件拷贝至D:\tmp\test.txt,但D:\tmp\test.txt已经存在。 //File.Copy(sourceFile,destinationFile,tr...
许多软件都有自动关机功能,特别是在长时间下载的时候,这个功能可是使你不用以守候在计算机前面,而电脑却能按照您事先的设定自动关闭。现在我们用visual C#来编写一个多功能的关机程序。该程序具有:定时关机、倒计时关机、关机提醒、系统信息获取等四项功能, 可设定关机时间精确到秒。并且让你很快掌握Visual C#中对API的操作程序。 一. ...
       在我们的开发项目中使用MVC(Model-View-Control)模式的益处是,可以完全降低业务层和应用表示层的相互影响。此外, 我们会有完全独立的对象来操作表示层。MVC在我们项目中提供的这种对象和层之间的独立,将使我们的维护变得更简单使 我们的代码重用变得很容易(下面你将看到)。 ...

经验教程

545

收藏

39
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部