委托C# 生活 实例
現實中的例子:
比如說一個公司(場景),你是老板,手下有兩個員工,小張和小王。
你命令小王,如果小張玩游戲,則小王扣去小張500元錢。
這就是現實中的委托。
實際上,在寫程序中,程序員就是老板,小張和小王就是兩個對象。小張玩游戲是一個方法,小張還有一個游戲事件,他玩游戲激發這個事件。而小王就是事件處理對象,他負責把小張的錢扣除500。
所以,委托有如下幾個要素:
1 激發事件的對象--就是小張
2 處理對象事件的對象--就是小王
3 定義委托,就是你讓小王監視小張。
如果這三個要素都滿足的話,則你就寫出了一個完整事件的處理。
下面有個例子:在vs.net2003 C#控制臺應用程序編輯運行成功:
using System;
namespace CSharpConsole
{
public class 場景
{
[STAThread]
public static void Main(string[] args)
{
Console.WriteLine("場景開始了....");
// 生成小王
小王 w = new 小王();
// 生成小賬
小張 z = new 小張();
// 指定監視
z.PlayGame += new PlayGameHandler(w.扣錢);
// 開始玩游戲
z.玩游戲();
console.writeline("場景結束...");
Console.ReadLine();
}
}
// 負責扣錢的人
public class 小王
{
public 小王()
{
Console.WriteLine("生成小王...");
}
public void 扣錢(object sender,EventArgs e)
{
Console.WriteLine("小王:好小子,上班時間膽敢玩游戲...");
Console.WriteLine("小王:看看你小子有多少錢...");
小張 f = (小張)sender;
Console.WriteLine("小張的錢: " + f.錢.ToString());
Console.WriteLine("開始扣錢......");
System.Threading.Thread.Sleep(500);
f.錢 = f.錢 - 500;
Console.WriteLine("扣完了....現在小張還剩下:" + f.錢.ToString());
}
}
// 如果玩游戲,則引發事件
public class 小張
{
// 先定義一個事件,這個事件表示“小張”在玩游戲。
public event PlayGameHandler PlayGame;
// 保存小張錢的變量
private int m_Money;
public 小張()
{
Console.WriteLine("生成小張....");
m_Money = 10000; // 構造函數,初始化小張的錢。
}
public int 錢 // 此屬性可以操作小張的錢。
{
get
{
return m_Money;
}
set
{
m_Money = value;
}
}
public void 玩游戲()
{
Console.WriteLine("小張開始玩游戲了.....");
Console.WriteLine("小張:CS好玩,哈哈哈! 我玩.....");
System.Threading.Thread.Sleep(500);
System.EventArgs e = new EventArgs();
//OnPlayGame(e);
if(PlayGame != null)
{
PlayGame(this,e);
}
}
protected virtual void OnPlayGame(EventArgs e)
{
if(PlayGame != null)
{
PlayGame(this,e);
}
}
}
// 定義委托處理程序
public delegate void PlayGameHandler(object sender,System.EventArgs e);
}
=========================================================
剛開始在理解委托和事件時常常被msdn搞糊涂,為了快速應用.net的委托和事件模型編程,可以先看看如下的代碼
using System;
namespace delegeteTest
{
class delegeteClass
{
public delegate void fHandler(int a); //關鍵-此行可以看成類的聲明
public fHandler f0;
public void d(int a,int b )
{
int c=a+b;
f0(c);
}
}
class test
{
public void output(int mun)
{
System.Console .WriteLine ("{0}",mun);
}
[stathread]
static void Main(string[] args)
{
test t=new test ();
delegeteClass dc=new delegeteClass ();
dc.f0 =new delegeteTest.delegeteClass.fHandler (t.output);//實例的初始化
dc.d(2,3);
}
}
}
解釋一下"關鍵": 實際上 public delegate void fHandler(int a);可以看成如下:
class fHandler
{.....}
類內部由編譯器自動完成,是一個sealed類通過反匯編可以看到,是一個類的聲明,它檢查加入自己的函數的信息,如,返回值和參數類型
現在熟悉vc++的人可能感覺到public delegate void fHandler(int a);這句就象一個宏
現在好了既然是個類的定義,那么也可以直接拿到命名空間下了
using System;
namespace delegeteTest
{
public delegate void fHandler(int a);//fHandler現在上升到了類的層次
class delegeteClass
{
public fHandler f0;//聲明了委托fHandler的實例f0;
public fHandler f1;//也可以再聲明一個fHandler類的實例f1;
public void d(int a,int b )
{
int c=a+b;
f0(c);
}
}
class test
{
public void output(int mun)
{
System.Console .WriteLine ("{0}",mun);
}
[stathread]
static void Main(string[] args)
{
test t=new test ();
delegeteClass dc=new delegeteClass ();
dc.f0 =new delegeteTest.fHandler (t.output);//此行做相應的修改
dc.d(2,3);
}
}
}
有以上可知public delegate void fHandler(int a)這行代碼只能放在能夠聲明類的地方,自然fHandler.后面的函數都是靜態方法了,如fHandler.Equals (...);
那么fhandler到底聲明了什么? 實際上是聲明了函數的類型,既函數的有關信息(如返回值,參數類型)。說到委托還是要說一下委托類型的實例。在msdn中的很多地方,(委托)這個詞指的是委托類型的實例,它擁有了一個列表,列表的每一項包含了函數信息和函數所在的對象的引用。
在聲明fhandler類的實例f0的時候,f0還不能用,是空的,所以f0需要初始化 dc.f0 =new delegeteTest.fHandler (t.output); 初始化的參數包含了兩個信息 t--對象的引用,output--函數信息,如果把初始化的這句注釋掉,你運行一下看有什么信息----“未將對象引用設置到對象的實例”。另外output函數的參數和返回值需要和fHandler的類聲明一致,這是由編譯器在編譯時檢查的。
經過初始化之后 現在實例中有了一項數據(實際上大多數只有一項,這樣效率比較高,也就是single cast的,此時實例是Delegate類型的(注意是大寫的D))。
現在說一下委托的多播(multi cast),實際上委托的多播就是把列表里的每一項函數調用一次),但是多播的效率不是很高的所以委托的大部分實例都是單播(single cast),另外可能委托的實例會根據列表內函數的個數來運行不同的機制(這里我們就沒必要研究它了)。看下面的代碼:
namespace delegeteTest
{
public delegate void fHandler(int a);
class delegeteClass
{
public fHandler f0;
public fHandler f1;
public void d(int a,int b )
{
int c=a+b;
f1(c); //合并指針列表的多播委托
}
}
class test
{
public void output(int mun)
{
System.Console .WriteLine (" 函數1顯示{0}",mun);
}
public void output1(int mun)
{
System.Console .WriteLine (" 函數2顯示{0}",mun);
}
[stathread]
static void Main(string[] args)
{
test t=new test ();
delegeteClass dc=new delegeteClass ();
dc.f0 =new delegeteTest.fHandler (t.output);
dc.f1 =new fHandler (t.output1 );
system.console .WriteLine ("第一次觸發");
dc.d (2,3);//第一次觸發
dc.f1 =(fHandler)Delegate.Combine (dc.f0 ,dc.f1 );//合并生成新的]函數列表
dc.f1 =(fHandler)MulticastDelegate.Combine (dc.f1 ,dc.f0 );//同上
System.Console .WriteLine ("第二次觸發");
dc.d(2,3);//第二次觸發
}
}
}
實際上dc.f1 =(fHandler)MulticastDelegate.Combine (dc.f1 ,dc.f0 );和dc.f1 =(fHandler)Delegate.Combine (dc.f1 ,dc.f0 );效果是一樣的;由上面的例子可知我們完全可以由delegate 來構造我們自己的事件。微軟為了方便大家進行編程,為我們提供了event。
using System;
namespace delegeteTest
{
public delegate void fHandler(int a);
class delegeteClass
{
public fHandler f0;
public fHandler f1;
public event fHandler f3; //關鍵--實際上此行也可以看成一個宏
public void d(int a,int b )
{
int c=a+b;
f3(c); // 改由event進行
}
}
class test
{
public void output(int mun)
{
System.Console .WriteLine (" 第1顯示{0}",mun);
}
public void output1(int mun)
{
System.Console .WriteLine (" 第2顯示{0}",mun);
}
[stathread]
static void Main(string[] args)
{
test t=new test ();
delegeteClass dc=new delegeteClass ();
dc.f0 =new delegeteTest.fHandler (t.output);
dc.f1 =new fHandler (t.output1 );
dc.f3 +=new fHandler(t.output); //f3是event
System.Console .WriteLine ("第一次觸發");
dc.d (2,3);//第一次觸發
system.console .WriteLine ("第二次觸發");
dc.f3 +=(fHandler)Delegate.Combine (dc.f0 ,dc.f1 );//添加列表到f3
dc.d(2,3);//第二次觸發
}
}
}
通過ildasm反匯編可以看到public event fHandler f3宏聲明了兩個成員
.field private class delegeteTest.fHandler f3和對f3的一個包裝:
.event delegeteTest.fHandler f3
{
.addon instance void delegeteTest.delegeteClass::add_f3(class delegeteTest.fHandler)
.removeon instance void delegeteTest.delegeteClass::remove_f3(class delegeteTest.fHandler)
},
所以上面部分代碼可以替換成如下:
private fHandler _f3;//由于不能與屬性名相同,所以用_f3,是私有
public event fHandler f3
{
add
{
this._f3 += value;
}
remove
{
this._f3 -= value;
}
}
event 關鍵字方便了大家的習慣,同時它(由event定義的事件)在類的外部使用時隱藏了它的成員函數(這一點非常重要,幾乎就是使用event關鍵字的原因),并且只能用“+=”和“-=”來操作,除此之外和直接聲明public fHandler f3沒有區別。它可以和上面的f0,f1一樣允許有各種參數和返回值。是在委托基礎上的。實際上我們都能用delegate 來構造我們想要的事件,這就是delegate 在.net里的地位很高的原因。
下面探討一般控件的事件模型
先談一下控件里的"on事件名"這個函數 如:OnTextChange(EventArgs e),類似的有很多,實際上這是一種編程方面的習慣,他代表的是引發這個TextChanged事件(注意不是代表TextChanged(e)的函數),具體的說就是在Text變量已經被賦值后執行的一個函數OnTextChanged(),OnTextChanged里面包含了類似TextChanged(e)這樣的引發事件的代碼。如果你重寫了OnTextChanged(),而沒有在(重寫的函數)里添加base.OnTextChanged(e);那么你在外部添加的TextChanged事件的處理程序,永遠也不會觸發到,也就是TextChanged事件失效了。
下面寫了一個重寫ontextchanged()的例子,是關于只能輸入數字的textbox, 里面有輸入整數部分的數量限制屬性 MaxOfInt 和小數限制屬性MaxOfLittle,還有decimal 類型的值 ValueDecimal屬性,還有一個DecmalValueChanged事件,由于重寫了OnTextChanged事件而沒有在里面寫base.TextChanged (e);所以你們如果再使用TextChanged事件就一點效果都沒有了。
下面的控件不怕粘貼,不怕漢字
using System;
using System.ComponentModel;
using System.ComponentModel .Design ;
namespace contr
{
/// <summary>
///
/// </summary>
public class TextBoxNum : System.Windows.Forms.TextBox
{
public delegate void ValueChangedHandler(object o,decimal DecValue);
private ValueChangedHandler ValueChanged;//聲明了一個實例
public int MaxInt=8;
public int MaxLittle=2;
public decimal DecimalValue=0;
public TextBoxNum()
{
//
// TODO: 在此處添加構造函數邏輯
//
}
private void InitializeComponent()
{
}
protected override void OnTextChanged(EventArgs e)
{
if(this.Text .Length !=0&&(this.Text[0])=='.')
{
this.Text ="0.";
this.SelectionStart=(this.Text .Length );
return;
}
string s=this.Text.Trim ();
if(this.MaxLittle ==0)
{
if(s.IndexOf ('.')>0||this.Text .Length >this.MaxInt )
{
this.Text =this.ValueDecimal .ToString ();
this.SelectionStart=(this.Text .Length );
return;
}
}
if(s ==""){return;}
int j=s .IndexOf ('.');
if((j<0&&s.Length >this.MaxInt ))
{
this.text =this.ValueDecimal .ToString ();
this.SelectionStart=(this.Text .Length );
return;
}
if(j>-1&&(s.Length -j-1)>this.MaxLittle)
{
this.Text =this.ValueDecimal .ToString ();
this.SelectionStart=(this.Text .Length );
return;
}
int a=0;
char[] temp=s.ToCharArray () ;
for(int i=0;i<s.Length ;i++)
{
if(Char.IsDigit(temp))
{
continue;
}
else if(temp=='.')
{
a++;
if(a>1)
{
this.Text =this.ValueDecimal .ToString ();
this.SelectionStart=(this.Text .Length );
return;
}
continue;
}
this.Text =this.ValueDecimal .ToString ();
this.SelectionStart=(this.Text .Length );
return;
}
this.ValueDecimal =decimal.Parse (this.Text);
base.TextChanged (e);
}
public event ValueChangedHandler DecmalValueChanged
{
add
{
this.ValueChanged += value;
}
remove
{
this.ValueChanged -= value;
}
}
public decimal ValueDecimal
{
get
{
return this.DecimalValue ;
}
set
{
this.DecimalValue =value;
if(ValueChanged!=null)
{
ValueChanged(this,this.DecimalValue );
}
}
}
[Browsable(true),DefaultValue(8)]
public int MaxOfInt
{
get
{
return this.MaxInt ;
}
set
{
if(value<=29)
{
this.MaxInt =value;
this.MaxLength =this.MaxLittle +value +1;
}
else
{
this.MaxInt =29;
this.MaxLength =this.MaxLittle +29 +1;
}
}
}
[Browsable(true),DefaultValue(2)]
public int MaxOfLittle
{
get
{
return this.MaxLittle ;
}
set
{
if(value<=29)
{
this.MaxLittle =value;
this.MaxLength =value +this.MaxInt +1;
}
else
{
this.MaxLittle =29;
this.MaxLength =29 +this.MaxInt +1;
}
}
}
}
}
總結
以上是生活随笔為你收集整理的委托C# 生活 实例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SSIS中的容器和数据流—举例说明数据转
- 下一篇: ABAP语言常用的系统字段及函数