樂高ev3機器人編程自學 [代理及其編程方法]
發(fā)布時間:2020-02-16 來源: 散文精選 點擊:
摘要:在C#語言中,可以用代理(Delegate)來動態(tài)地調用不同的函數。本文針對代理的基本概念、用代理編程的基本結構及多重代理進行討論,并通過實例程序進行必要的說明。
關鍵詞:函數指針;代理;多重代理
中圖分類號:TP312 文獻標識碼:A
1 代理的基本概念
在C/C++中,函數調用有兩種方式:一種是通過函數名直接調用;另一種是利用指向函數的指針進行調用。指向函數的指針又簡稱為函數指針。采用函數指針調用函數,可以達到通過一個函數指針調用多個功能不同、但函數的參數及返值類型一致的函數。
1.1 函數指針
在C/C++中,函數名表示函數在存儲區(qū)域的首地址,即是函數執(zhí)行的入口地址。在程序中調用一個函數時,程序控制流程將轉移到以該函數名為入口地址的地方執(zhí)行該函數。
函數指針定義的一般形式是:
數據類型(*函數指針名)(參數表);
其中數據類型是函數指針所指向的函數所具有的返值類型,參數表是被調函數所具有的參數表。
一般來講,函數指針得到某個函數名的賦值,程序將調用該函數;在函數指針作為函數的形參時,需要進行取內容的運算才能調用對應的函數。例如:
exe(int x,int y,int (*func)())
{ return((*func)(x,y));}
在上述exe函數中,int (*func)()是函數指針,而“((*func)(x,y));”程序將轉向由func所指向的函數去執(zhí)行,其參數是x和y。
使用函數指針編程方法一般為:定義相應的函數;定義函數指針;通過某種操作使函數指針得到函數名的賦值;最后連同參數調用相應的函數。
1.2 代理及其相關概念
在C#中,代理(delegate)的作用類似于C/C++中的函數指針。C#中的方法類似于C/C++中的函數,其方法名也是一個物理地址。方法的入口地址可以賦給“代理”,進而通過“代理”調用該方法;且同一個代理可以調用多個不同的方法。使用代理可以在程序的運行期間動態(tài)地調用所需的函數。
代理定義的一般格式為:
[訪問控制修飾符] delegate返值類型 代理名([形式參數表]);
其中:訪問控制修飾符可以是new、public、protected、internal和private。new修飾符表明當前定義的代理將隱藏繼承來的同名代理;public修飾符表明所有對象都可以訪問該定義的代理;protected修飾符表明定義該代理的類及其子類可以訪問該代理;internal修飾符只有代理所屬的工程項目的成員可以訪問該代理;private修飾符表明只有定義該代理的類才能訪問該代理。
delegate是定義代理的關鍵字。代理名是符合C#的任意合法的標識符。返值類型是指該代理所調用方法的返值類型。形式參數表用于指出代理所調用方法的參數表。
例如,在一個類中定義一個代理MyDel_ egate:
classMyClass
{ ……
public delegate void MyDelegate(string s);
……
}
在上述代理定義中的void表示該代理指向的方法不返回任何值,string s表示該代理所指向的方法將接受一個字符串參數。
在C#中,定義一個代理MyDelegate, C#編譯器將根據代理的定義語句自動生成一個從System.MulticastDelegate類派生的子類MyDelegate。
2 使用代理的編程結構
代理類似于C/C++的指向函數的指針,但是代理的使用范圍比函數指針更加廣泛。在C中,函數只有外部和靜態(tài)函數兩種,它們都屬于靜態(tài)函數的范疇;在C ++中,函數指針只能引用靜態(tài)方法,而代理不僅可以引用靜態(tài)方法,還可以引用對象的實例方法。
2.1 使用代理的編程結構
使用代理編程和在C/C++中使用函數指針類似,一般有:定義將要由代理調用的方法;聲明一個代理;定義delegate處理的函數;創(chuàng)建實例并調用相應方法。
(1)定義擬調用的方法
該類方法的函數返值類型,函數形參的參數類型、個數及參數的順序,決定了定義delegate類型代理時的相應參數。例如:
public static string FunctionA
(string name) {……}
public static string FunctionB
。╯tring name) {……}
。2)聲明一個代理
該代理的返值類型,參數的類型、個數及參數的順序都必須與擬調用的方法的返值類型,形參類型、個數及參數的順序完全相同。例如:
public delegate string MyDelegate (stringname);
(3)定義delegate類型處理的函數
定義delegate類型處理的函數,并在此函數中通過delegate類型調用定義的方法。
public static void MethodA(MyDelegateMe)
{Console.WriteLine(Me(“張三”));}
。4)創(chuàng)建實例并調用方法
由于聲明一個delegate類型的代理在編譯時將被轉換成一個MulticastDelegate類的派生類,因此在使用代理時,必須要先創(chuàng)建該類的實例,并把它與一個方法關聯。
MyDelegate a=new MyDelegate (FunctionA)
本語句的含義是:a引用指向方法FunctionA的程序代碼段。
通過delegate處理函數調用相應的方法。MethodA(a);
2.2 使用代理編程實例
using System;
namespace ConDelegatejl
{ public class Test
{ //第一步:聲明委托
public static string FunctionA(string name)
{return“A say Hello to”+name;}
public static string FunctionB(string name)
{return “B say Hello to ”+name;}
//第二步:定義被調用的方法
public delegate string MyDele gate(string name);
//第三步:定義delegate類型處理函數
public static void MethodA (MyDelegate Me)
{Console.WriteLine(Me(“張三”));}
public static void Main()
{ //第四步:創(chuàng)建實例,
//準備調用的方法名
MyDelegate a = new MyDelegate (FunctionA);
MyDelegate b = new MyDelegate (FunctionB);
MethodA(a); MethodA(b); Console.Read();
}
}
上述程序的運行結果如下圖所示。
3 多重代理及其實現
在C#語言中,每一個代理實例(對象)都含有一個調用鏈表,該鏈表可以包含多個該代理要調用的方法,此種機制用于一個代理實例可以調用多個方法,也就是多重代理(多播)。多播要創(chuàng)建方法鏈表,當調用代理時,所有被鏈接的方法都會被自動地調用。
3.1 Delegate類和MulticastDelegate類
所有的代理類都是由MulticastDele gate類派生的,而MulticastDelegate類又是由Delegate類派生的,它們都位于System命名空間下。
Delegate類有兩個公用的只讀屬性:
Method屬性:本屬性用于獲得代理實例要調用的靜態(tài)方法?梢杂萌缦麓a獲得代理對象所調用的方法名。
stringMethodName=代理名.Method;
Target屬性:該屬性可以獲得代理對象所在的類;如果代理調用的是靜態(tài)方法,其返值為null,否則將返回代理實例所調用方法所在類名。如下代碼可以獲得代理調用方法所在類的名稱。
stringObjType=代理名.Target;
如果代理調用多個方法,則該屬性將返回調用列表中最后一個實例方法所在的類名。
3.2 MulticastDelegate類實現多重代理的機制
從MulticastDelegate類派生的用戶代理實例中含有一個調用鏈表,該鏈表將由多個代理實例組成,其中每個代理實例都封裝一個相應的方法,也就是一個代理實例可以同時調用多個方法。代理實例通過_prev私有指針來連接多個代理構成的鏈表,私有指針_target和_methodPtr用于指向代理實例調用的實例和方法。
每創(chuàng)建一個新的代理實例時,指針_prev將被設置為null,表示鏈表中沒有其它的代理實例。而當用戶使用Combine方法(或+=運算符)把另一個代理實例合并到該調用鏈表中時,則將先創(chuàng)建一個含有_target和_methodPtr值的新實例,然后把該實例的_prev設置為調用鏈表的頭實例,即從調用鏈表的頭插入新的實例?梢允褂肦emove方法(或-=運算符)從一個調用鏈表中刪除一個代理實例。
3.3 多重代理編程的實現
多重代理(或多播)具有創(chuàng)建方法鏈表的能力,當調用代理時,所有被鏈接的方法都會被自動調用,也就是多播可以在一次代理調用中調用方法鏈表上的所有方法。創(chuàng)建多播調用鏈表的方法是:先實例化一個代理,然后使用“+=”運算符把方法添加到調用鏈表中;也可以使用“-=”運算符從調用鏈表中刪除一個方法。
下面程序說明了多重代理編程的實現方法。
using System;
using System.Collections.Generic;
using System.Text;namespace ConDelegatej2
{
delegate void StringDelegate(
ref string str);//定義一個代理
class stringops//字符串操作類
{ //定義三個字符串操作方法
static void ReplaceSpaces(ref string s)
{ Console.WriteLine("用連字符替換
空格操作:");
s = s.Replace(" ", "_");
}
static void RemoveSpaces(ref string s)
{ string temp = "";int i;
Console.WriteLine("刪除空格操作:");
for(i=0; i=0;j--)
temp += s[j];
s = temp;
}
static void Main(string[]args)
{//創(chuàng)建一個代理
StringDelegate strdelegate;
StringDelegate replacesp=new
StringDelegate(ReplaceSpaces);
StringDelegate removes =new
StringDelegate(RemoveSpaces);
StringDelegate reversestr=new StringDelegate(Reverse);
string str = "Iam astudent.";
//代理指向一個函數
strdelegate =replacesp;
strdelegate += reversestr;//多播關聯
strdelegate(ref str );//調用多播
Console.WriteLine("操作字符串的結果為:"+str);
Console.WriteLine();
strdelegate-=replacesp;//去除replacesp
strdelegate += RemoveSpaces;
str ="你是一個計算機教師.";
strdelegate (refstr);
Console.WriteLine("字符串操作結果是:"+str);
Console.WriteLine ();Console.Read();
}
}
}
上述程序的運行結果如下所示。
4 結束語
代理是C#語言提供動態(tài)調用函數的一種方法;多重代理解決了用一個代理一次調用多個方法的技術。不過代理的多播有一個限制:方法鏈表中的方法必須具有相同的參數,而且這些方法的返回值類型要是void類型。
代理也為用戶程序利用屬性驅動事件程序的編程提供了有力的方法。
參考文獻
[1]唐大仕編著. C#程序設計教程[M]. 北京: 清華大學出版社; 北方交通大學出版社, 2003.
[2]邵鵬鳴編著. Visual C#程序設計基礎教程[M]. 北京: 清華大學出版社, 2005.
相關熱詞搜索:編程 代理 方法 代理及其編程方法 編程通訊線代理 可編程觸摸屏代理
熱點文章閱讀