Lazy_Allocate(缓分配)

它可以让对象节省一些内存成本

public class myclass
{
private DataSet _ds;
public DataSet ds
{
get
{
if(_ds==null)//如果没有创建实例,则创建一个新的
{
_ds=new DataSet();
}
return _ds;
}
}
}

Static Helper Object

sealed关键字可以防止类被继承.static可以定义类的静态变量或静态函数.

public sealed class mystring
{
public static string getHello()
{
return "Hello World!";
}
}

这样可以通过mystring.getHello()取得字符串"Hello World!"

Helper Object的中心概念就是将常用的辅助型函数包装成静态函数,设计人员无需重复撰写这些程序代码

Event
c#中Event于delegate是密切相关的,delegate翻译过来就是委托,其实就是函数指针.

以下代码是delegate的最简单的应用示例,会在浏览器端输出Hello World!

public delegate void mydele(string a);
public class delegatetest : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
mydele md=new mydele(output);
md("Hello World!");
}

public void output(string a)
{
Response.Write(a);
}
#region Web 窗体设计器生成的代码
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);


}
#endregion
}

event 关键字使您得以指定当代码中的某些“事件”发生时调用的委托。此委托可以有一个或多个关联的方法,当代码指示该事件已发生时将调用关联的方法。可使一个程序中的事件用于面向 .NET Framework 公共语言运行库的其他程序。

为了创建并使用 C# 事件,必须采取以下步骤:

  1. 创建或标识一个委托。如果正在定义自己的事件,还必须确保有与事件关键字一起使用的委托。如果已经预定义了事件(例如在 .NET Framework 中),则事件的使用者只需要知道委托的名称。
  2. 创建一个类,包含:
    1. 从委托创建的事件。
    2. (可选)验证用 event 关键字声明的委托实例是否存在的方法。否则,该逻辑必须放置在引发此事件的代码中。
    3. 调用此事件的方法。这些方法可以重写一些基类功能。
    此类定义事件。

  3. 定义一个或多个将方法连接到事件的类。所有这些类都包括:
    • 使用 += 运算符和 -= 运算符将一个或多个方法与基类中的事件关联。
    • 将与事件关联的方法的定义。
  4. 使用此事件:
    • 创建包含事件声明的类对象。
    • 使用定义的构造函数,创建包含事件定义的类对象。

下面示例代码改编自MSDN:


using System;
namespace MyCollections
{
using System.Collections;
//定义委托
public delegate void ChangedEventHandler(object sender, EventArgs e);
//该类功能与ArrayList一样,但是添加了当其内容被修改时的事件
public class ListWithChangedEvent: ArrayList
{
//定义事件的名称
public event ChangedEventHandler Changed;
// 内部方法,每一个内部修改的方法都调用它
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
Changed(this, e);
}
//覆写每一个类内部修改的方法,使修改的时候事件被触发
public override int Add(object value)
{
int i = base.Add(value);
OnChanged(EventArgs.Empty);
return i;
}
public override void Clear()
{
base.Clear();
OnChanged(EventArgs.Empty);
}
public override object this[int index]
{
set
{
base[index] = value;
OnChanged(EventArgs.Empty);
}
}
}
}
namespace TestEvents
{
using MyCollections;
class EventListener
{
private ListWithChangedEvent List;

//构造函数
public EventListener(ListWithChangedEvent list)
{
List = list;
//添加List的changed事件,使触发时调用ListChanged方法
List.Changed += new ChangedEventHandler(ListChanged);
}
// 触发时调用的ListChanged方法
private void ListChanged(object sender, EventArgs e)
{
Console.WriteLine("This is called when the event fires.");
}
public void Detach()
{
// 将与事件关联的方法分离,并将list从内存清除
List.Changed -= new ChangedEventHandler(ListChanged);
List = null;
}
}
class Test
{
public static void Main()
{
// 创建ListWithChangedEvent的实例
ListWithChangedEvent list = new ListWithChangedEvent();
// 创建list的侦听类的实例
EventListener listener = new EventListener(list);
// list执行添加和清空项的操作
list.Add("item 1");//这里触发一次changed的事件
list.Clear();//这里触发一次changed的事件
listener.Detach();
}
}
}

以下是MSDN给出的代码解释:

声明事件 若要在类内声明事件,首先必须声明该事件的委托类型(如果尚未声明的话)。
public delegate void ChangedEventHandler(object sender, EventArgs e);
委托类型定义传递给处理该事件的方法的一组参数。多个事件可共享相同的委托类型,因此仅当尚未声明任何合适的委托类型时才需要执行该步骤。
接下来,声明事件本身。
public event ChangedEventHandler Changed;
声明事件的方法与声明委托类型的字段类似,只是关键字 event 在事件声明前面,在修饰符后面。事件通常被声明为公共事件,但允许任意可访问修饰符。
调用事件 类声明了事件以后,可以就像处理所指示的委托类型的字段那样处理该事件。如果没有任何客户将委托与该事件挂钩,该字段将为空;否则该字段引用应在调用该事件时调用的委托。因此,调用事件时通常先检查是否为空,然后再调用事件。
if (Changed != null)
Changed(this, e);
调用事件只能从声明该事件的类内进行。
与事件挂钩 从声明事件的类外看,事件像个字段,但对该字段的访问是非常受限制的。只可进行如下操作:
在该字段上撰写新的委托。
从字段(可能是复合字段)移除委托。
使用 += 和 -= 运算符完成此操作。为开始接收事件调用,客户代码先创建事件类型的委托,该委托引用应从事件调用的方法。然后它使用 += 将该委托写到事件可能连接到的其他任何委托上。

// Add "ListChanged" to the Changed event on "List":
List.Changed += new ChangedEventHandler(ListChanged);

当客户代码完成接收事件调用后,它将使用运算符 -= 从事件移除其委托。

// Detach the event and delete the list:
List.Changed -= new ChangedEventHandler(ListChanged);

MSDN的示例代码中有一个中间的EventListener类,看起来可能不大好理解,我自己写了一个,难度比MSDN上提供的简单些:

namespace DesignPattern
{
/// <summary>
/// eventtest 的摘要说明。
/// </summary>
using myns;
public class eventtest : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
Data d=new Data();
d.Added+=new ChangedHandler(this.add);
d.ReLoaded+=new ChangedHandler(this.reload);
d.Add(5);
d.ReLoad();
}
private void add(object sender,System.EventArgs e)
{
Response.Write("add finish<br>");
}
private void reload(object sender,System.EventArgs e)
{
Response.Write("reload finish<br>");
}
#region Web 窗体设计器生成的代码
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
//
InitializeComponent();
base.OnInit(e);
}

/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
}

}
namespace myns
{
public delegate void ChangedHandler(Object sender,System.EventArgs e);
//一个超级简单的数据类,里面只有一个int变量,类只有最简单的加和归零2个方法,定义了2个事件
public class Data
{
private int i=0;
public event ChangedHandler Added;
public event ChangedHandler ReLoaded;
protected void OnAdd(EventArgs e)
{
if(Added!=null)Added(this,e);
}
protected void OnReLoad(EventArgs e)
{
if(ReLoaded!=null)ReLoaded(this,e);
}
public void Add(int key)
{
i+=key;
OnAdd(EventArgs.Empty);
}
public void ReLoad()
{
i=0;
OnReLoad(EventArgs.Empty);
}
public int getNum()
{
return i;
}
}
}


Programming With Reflection
Reflection的主要用途是执行时期提供类型信息。
在.NET FRAMEWORK中,Reflection通过Type对象来操作。

其中分成2部分:
一是提供Type本身的信息,比如public、sealed等等,直接通过IsPublic等属性获得;
二是提供Type内成员信息,返回值为MemberInfo或其派生类的实例,比如GetConstructor(s)返回ConstructorInfo对象或数组、GetField(s)返回FieldInfo对象或数组。

关于Type类的详细信息请参看
http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/cpref/html/frlrfsystemtypememberstopic.asp

Dynamic Invoke

Reflection允许设计人员动态调用函数。可以通过MethodInfo对象的Invoke方法调用,也可以直接通过Type的InvokeMember来调用。


namespace DesignPattern
{
/// <summary>
/// reflectiontest 的摘要说明。
/// </summary>
public class reflectiontest : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
MyData md=new MyData(10);
object[] o=new object[]{1};
o[0]=5;

Type t=typeof(MyData);//获取MyData的Type信息
MethodInfo mi=t.GetMethod("Zero");
mi.Invoke(md,null);//通过MethodInfo对象的Invoke方法调用md的Zero
Response.Write(md.getnum());
t.InvokeMember("setnum", BindingFlags.InvokeMethod ,null,md,o);//通过Type的InvokeMember调用md的setnum
Response.Write(t.InvokeMember("getnum",BindingFlags.InvokeMethod,null,md,null));
}
#region Web 窗体设计器生成的代码
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
//
InitializeComponent();
base.OnInit(e);
}

/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
}

//一个简单的类,有一个int的私有成员,公共方法有归0,赋值以及获取。
public class MyData
{
private int i;
public MyData(int a)
{
i=a;
}
public void Zero()
{
i=0;
}
public void setnum(int a)
{
i=a;
}
public int getnum()
{
return i;
}
}
}

写Reflection的时候别忘了using System.Reflection;

Collection

Collection是指聚集一群元素的容器,概念由数组延伸而来。

1、IEnumerable接口。实现该接口的对象可使用foreach。IEnumerable接口只预定义一个函数GetEnumerator,返回一个IEnumerator对象实例。

以下是代码实例:


public class MyEnumerator:IEnumerator
{
private int _index;
private string[] _list;
public MyEnumerator(string[] list)
{
_index=-1;
_list=list;
}
public void Reset()
{
_index=-1;
}
public object Current
{
get
{
return _list[_index];
}
}
public bool MoveNext()
{
_index++;
if(_index>=_list.Length)
{
_index=_list.Length-1;
return false;
}
return true;
}
}
public class MyEnumerable:IEnumerable
{
private string[] _list;
public MyEnumerable()
{
_list=new string[3]{"1","2","3"};
}
public IEnumerator GetEnumerator()
{
return new MyEnumerator(_list);
}
}

有了以上实现了IEnumerator和IEnumerable接口的类后,通过以下代码可以输出123

MyEnumerable me=new MyEnumerable();
foreach(string s in me)Response.Write(s);

2、ICollection接口是IEnumerable的加强型接口

public interface ICollection:IEnumerable
{
int Count{get;}
object SyncRoot{get;}
bool IsSynchronized{get;}
void CopyTo(Array array,int index);
}

以下代码的类实现了ICollection接口

public class MyCollection:ICollection
{
private string[] _list;
private object _root;
public MyCollection()
{
_list=new string[3]{"1","2","3"};
}
public bool IsSynchronized
{
get
{
return true;
}
}
public int Count
{
get
{
return _list.Length;
}
}
public void CopyTo(Array array, int index)
{
_list.CopyTo(array,index);
}
public object SyncRoot
{
get
{
return _root;
}
}
public IEnumerator GetEnumerator()
{
return _list.GetEnumerator();
}
}

3、IList接口提供了修改Collection内部元素的能力。事实上它是IEnumerable和ICollection接口的综合体。
其原型如下

public interface IList:ICollection,IEnumerable
{
object this[int index]{get;set;}
bool IsReadOnly{get;}
bool IsFixedSize{get;}
int Add(object value);
bool Contains(object value);
void Clear();
int IndexOf(object value);
void Insert(int index,object value);
void Remove(object value);
void RemoveAt(int index);
}
下面是一个实现了IList接口的类
public class MyList:IList
{
private ArrayList _list;
public MyList()
{
_list=new ArrayList();
}
#region IList 成员
public bool IsReadOnly
{
get
{
return false;
}
}
public object this[int index]
{
get
{
return _list[index];
}
set
{
_list[index]=value;
}
}
public void RemoveAt(int index)
{
_list.RemoveAt(index);
}
public void Insert(int index, object value)
{
_list.Insert(index,value);
}
public void Remove(object value)
{
_list.Remove(value);
}
public bool Contains(object value)
{
return _list.Contains(value);
}
public void Clear()
{
_list.Clear();
}
public int IndexOf(object value)
{
return _list.IndexOf(value);
}
public int Add(object value)
{
return _list.Add(value);
}
public bool IsFixedSize
{
get
{
return false;
}
}
#endregion
#region ICollection 成员
public bool IsSynchronized
{
get
{
return _list.IsSynchronized;
}
}
public int Count
{
get
{
return _list.Count;
}
}
public void CopyTo(Array array, int index)
{
_list.CopyTo(array,index);
}
public object SyncRoot
{
get
{
return _list.SyncRoot;
}
}
#endregion
#region IEnumerable 成员
public IEnumerator GetEnumerator()
{
return _list.GetEnumerator();
}
#endregion
}

4、前面几个接口都使用object作为Collection中的元素类型,这样所有对象都可以放入Collection中,但是,这种设计过于松散,容易产生混用,有时候需要一个Strong-Type Collection。
针对设计人员对Strong-Type Collection的需求,.NET FRAMEWORK提供了一个CollectionBase的基础类。
下面是一个简单范例,代码中的List是CollectionBase中一个protected IList,它包含CollectionBase 实例中元素的列表。


public class Int16Collection : CollectionBase {
public Int16 this[ int index ] {
get {
return( (Int16) List[index] );
}
set {
List[index] = value;
}
}
public int Add( Int16 value ) {
return( List.Add( value ) );
}
public int IndexOf( Int16 value ) {
return( List.IndexOf( value ) );
}
public void Insert( int index, Int16 value ) {
List.Insert( index, value );
}
public void Remove( Int16 value ) {
List.Remove( value );
}
public bool Contains( Int16 value ) {
return( List.Contains( value ) );
}
}

CodeDOM


它是.net framework中产生程序代码的基础建设,它以对象化方式仿真出程序代码的逻辑,最后交给特定Code Provider对象(e.g. CSharpCodeProvider)产生源程序代码。

CodeCompileUnit是CodeDOM中根容器型对象。
CodeNamespace对象可以产生namespace语句。
CodeTypeDeclaration可以用来产生声明类型的对象,可以处理类、枚举、接口、结构。
CodeMemverField、CodeMemberMethod、CodeMemberProperty和CodeMemberEvent分别可以产生成员变量、方法、属性和事件。
指定CodeMemberMethod的ReturnType可以指定返回值类型,通过添加CodeMethodReturnStatement对象产生return代码。
添加Paramerters可以指定方法传递的参数。

以下是示例代码:


using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.CodeDom;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.IO;

namespace DesignPattern
{
/// <summary>
/// codedomtest 的摘要说明。
/// </summary>
public class codedomtest : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
//创建根容器对象
CodeCompileUnit unit=new CodeCompileUnit();
//创建产生源代码的Provider对象
CodeDomProvider provider=new CSharpCodeProvider();
//创建产生NameSpace的对象
CodeNamespace cns=new CodeNamespace("MyNamespace");
//创建NameSpace的包含对象
CodeNamespaceImport cnsi=new CodeNamespaceImport("System");
cns.Imports.Add(cnsi);
//创建生成类的对象
CodeTypeDeclaration ctd=new CodeTypeDeclaration("MyClass");
ctd.IsClass=true;
//创建类的成员函数
CodeMemberField cmf=new CodeMemberField(typeof(int),"one");
ctd.Members.Add(cmf);
//创建类的方法
CodeMemberMethod cmm=new CodeMemberMethod();
cmm.Name="getNum";
cmm.ReturnType=new CodeTypeReference(typeof(int));
cmm.Attributes=MemberAttributes.Public;
cmm.Statements.Add(new CodeMethodReturnStatement(new CodeArgumentReferenceExpression("one")));
ctd.Members.Add(cmm);
cns.Types.Add(ctd);
unit.Namespaces.Add(cns);
//将代码生成到d:\test.cs
ICodeGenerator gen=provider.CreateGenerator();
StreamWriter sw=new StreamWriter("d:\\test.cs",false);
gen.GenerateCodeFromCompileUnit(unit,sw,new CodeGeneratorOptions());
sw.Close();
}
#region Web 窗体设计器生成的代码
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
//
InitializeComponent();
base.OnInit(e);
}

/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
}
}
生成的test.cs如下:
namespace MyNamespace {
using System;


public class MyClass {

private int one;

public virtual int getNum() {
return one;
}
}
}

Attribute

我的理解为特性。它像标签一样可以贴在类、方法、变量上。我们可以使用它定义设计层的信息或定义运行时信息。
预定义的Attribute要继承自System.Attribute。以下是示例:


[AttributeUsage(AttributeTargets.All,Inherited=false,AllowMultiple=false)]
public class DescribeAttribute:Attribute
{
private string _AddName;
public string AddName
{
get
{
return _AddName;
}
set
{
_AddName=value;
}
}
public DescribeAttribute(string a)
{
_AddName=a;
}
}

AttributeUsage代表了Attribute适用的情况。第一个参数是该Attribute适用的情况,第二个参数代表是否该Attribute会随着继承被继承,第三个参数代表同一目标能否被重复贴上该Attribute。
如下代码定义了一个贴上了以上定义的Attribute的class:


[Describe("This is my Attribute Test.")]
public class AttrTest
{
public AttrTest()
{
}
}

Attribute一般被绑定于Type上,可以通过Type.GetCustomAttributes获得:


DescribeAttribute[] da=(DescribeAttribute[])typeof(AttrTest).GetCustomAttributes(typeof(DescribeAttribute),false);
foreach(DescribeAttribute dada in da)
Response.Write(dada.AddName);

Attribute可以绑定于方法或变量上,下面是将Attribute绑定到方法上的代码:

[Describe("This is a class.")]
public class AttrTest
{
public AttrTest()
{

}
[Describe("This is a method.")]
public void TestMethod()
{

}
}

成员上的方法通过Reflection的MethodInfo.GetCustomAttributes获得(如果获得成员变量上的Attribute就要用FieldInfo类):


foreach(MethodInfo method in typeof(AttrTest).GetMethods())
{
foreach (DescribeAttribute attr in method.GetCustomAttributes(true))
{
Response.Write(attr.AddName);
}
}

Attribute标识符
Attribute标识符可以声明Attribute的放置位置。
[assembly: Help("this a do-nothing assembly")]
以上程序告诉编译器Help属性用于整个程序集。
可用的标识符包括:

assembly
module
type
method
property
event
field
param
return

参考:

《深入剖析ASP.NET组件设计》
MSDN网站
CSDN网站