2009-07-06 60 views
7

我一直在想,代表如何可以有用,我們爲什麼要使用它們?其他則是Visual Studio文檔中的類型安全和所有這些優點,代表的真實世界用途是什麼。C#(或其他語言)代表的使用

我已經找到了一個,它非常有針對性。

using System; 

namespace HelloNamespace { 

    class Greetings{ 
    public static void DisplayEnglish() { 
      Console.WriteLine("Hello, world!"); 
    } 
    public static void DisplayItalian() { 
      Console.WriteLine("Ciao, mondo!"); 
    } 
    public static void DisplaySpanish() { 
      Console.WriteLine("Hola, imundo!"); 
     } 
    } 

    delegate void delGreeting(); 

    class HelloWorld { 
     static void Main(string [] args) { 

    int iChoice=int.Parse(args[0]); 
    delGreeting [] arrayofGreetings={ 
      new delGreeting(Greetings.DisplayEnglish), 
      new delGreeting(Greetings.DisplayItalian), 
      new delGreeting(Greetings.DisplaySpanish)}; 

    arrayofGreetings[iChoice-1](); 
     } 
    } 
} 

但是,這並不表明我到底使用委託,而不是有條件的優勢,「如果... {}」,它解析參數和運行方法。

有誰知道爲什麼它是更好地在這裏使用委託,而不是「如果... {}」。你還有其他的例子可以證明代表的有用性。

謝謝!

+0

啊,那是的多尼斯·馬歇爾的Visual C#2008年的第一個例子...不是真正合適的第一個Hello World示例,但仍然... – 2009-07-06 08:24:06

+0

不,我發現它在同一作者的「編程Microsoft Visual C#2005:語言」,好,他爲C#2008做了一個新版本,我將有一個看看吧 – 2009-07-06 08:34:52

回答

5

最常見的真實世界的日常使用代表說我可以想到在C#中將事件處理。當你在WinForm上有一個按鈕,並且當按鈕被點擊時你想要做某些事情,那麼你所做的是你最終註冊一個委託函數,當它被點擊時被按鈕調用。

所有這一切都發生自動爲您在由Visual Studio本身生成的代碼在幕後,所以你可能看不到它發生在哪裏。

一個真實世界的情況下可能會更對你有用是,如果你想使人們可以用將讀取的數據從互聯網飼料庫,並通知他們當飼料已被更新。通過使用委託,那麼使用庫的程序員將能夠在更新訂閱源時調用自己的代碼。

5

委託是的注入功能入的方法的最佳方式。因此,他們極大地幫助代碼重用

想想看,假設你有一組具有幾乎相同的功能,但在短短的幾行代碼的變化相關方法。您可以將這些方法共有的所有內容重構爲單一方法,然後您可以通過委託注入專用功能。

以LINQ使用的所有IEnumerable擴展方法爲例。所有這些定義常見功能,但需要一個委託傳遞給他們定義返回數據是如何預測,或如何將數據篩選,排序等..

4

Lambda表達式
代表主要與事件一起使用。但動態語言顯示了它們更廣泛的用途。這就是爲什麼我們得到Lambda expressions之前,代表們一直沒有得到充分利用,直到C#3.0。使用Lambda表達式(生成委託方法)很容易做到這一點

現在想象一下你有一個IEnumerable字符串。您可以輕鬆定義委託(使用Lambda表達式或任何其他方式)並將其應用於每個元素上(例如修剪多餘空間)。並且不使用循環語句。當然你的代表可能會做更復雜的任務。

1

代表用於在其他類中「調用」代碼(可能不一定在相同,類或者.cs中,甚至是相同的程序集中)。

在你的例子中,委託可以簡單地被if語句取代,如你所指出的那樣。

但是,委託是指向代碼中某處「活」的函數的指針,因爲組織原因,例如您無法訪問(輕鬆)。

0

另一個我覺得很有用的用法是如果我希望執行相同的操作,傳遞相同的數據或在同一對象類型的多個實例中觸發相同的操作。

3

我將嘗試列出一些例子,是超越了簡單的if-else場景:

  1. 實現回調。例如,您正在解析XML文檔,並且希望在遇到特定節點時調用特定函數。您可以將代表傳遞給函數。

  2. 實施策略設計模式。將委託分配給所需的算法/策略實施。

  3. 匿名委託在你希望某個功能在單獨的線程上執行的情況下(並且這個功能沒有任何東西可以發送回主程序)。

  4. 其他人建議的事件訂閱。

2

在您的例子您greating是相同的,所以你真正需要的是一個字符串數組。

如果您希望獲得使用Command模式代表的,假設有:

public static void ShakeHands() 
{ ... } 

public static void HowAreYou() 
{ ... } 

public static void FrenchKissing() 
{ ... } 

可以替代的方法具有相同簽名,但不同的動作。 你選擇的方式太簡單了,我的建議是 - 去找一本C#的深度書。

0

在.NET中,從後臺線程更新UI時也需要委託。由於您不能從與創建控件的線程不同的線程更新控件,因此您需要使用創建線程的上下文(主要使用this.Invoke)來調用更新代碼。

1

代表和相關語法糖有顯著改變了C#世界(2.0+) 委託是類型安全的函數指針 - 所以您使用委託任何你想要調用/在時間未來點執行代碼塊。

廣泛的部分,我能想到的

回調/事件處理程序:這樣做時EventX發生。或者當您準備好使用異步方法調用的結果時執行此操作。

myButton.Click += delegate { Console.WriteLine("Robbery in progress. Call the cops!"); } 

LINQ:選擇您想要向下傳遞管道之前做的每個元素的東西元素的投影等。例如選擇均勻的所有數字,然後返回每個數字的平方

var list = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } 
       .Where(delegate(int x) { return ((x % 2) == 0); }) 
       .Select(delegate(int x) { return x * x; });  
// results in 4, 16, 36, 64, 100 
2

下面是一個真實世界的例子。我在包裝某種外部電話時經常使用委託。例如,我們有一箇舊的應用程序服務器(我希望它會消失),我們通過.Net遠程連接來連接。我會打電話給在一個委託的應用服務器從這樣一個「safecall」功能:

private delegate T AppServerDelegate<T>(); 

private T processAppServerRequest<T>(AppServerDelegate<T> delegate_) { 
      try{ 
       return delegate_(); 
      } 
      catch{ 
       //Do a bunch of standard error handling here which will be 
       //the same for all appserver calls. 
      } 

     } 

//Wrapped public call to AppServer 
public int PostXYZRequest(string requestData1, string requestData2, 
    int pid, DateTime latestRequestTime){ 
      processAppServerRequest<int>(
       delegate { 
       return _appSvr.PostXYZRequest(
        requestData1, 
        requestData2, 
        pid, 
        latestRequestTime); 
       }); 

顯然錯誤處理做了一些比這更好的,但你得到的粗略的想法。

3

代表只是.Net的first class functions的實現,並允許使用它們的語言提供Higher Order Functions

這種風格的主要好處是可以將公共方面抽象爲一個函數,它只需要執行它(例如遍歷數據結構)並提供另一個函數(或多個函數)即可要求隨着事情順利進行。

規範化的功能實例是mapfold,可以通過提供其他操作來改變它以做各種事情。

如果你想總結一個T的列表並且有一些函數add需要兩個T並且把它們加在一起然後(通過部分應用)fold add 0變成總和。 fold multiply 1將成爲產品,fold max 0最大。在所有這些例子中,程序員都不需要考慮如何遍歷輸入數據,不用擔心輸入爲空時該怎麼做。

這些都是簡單的例子(儘管它們與其他結合起來可能會令人驚訝的強大),但考慮樹遍歷(更復雜的任務),所有這些都可以抽象出treefold函數。樹形摺疊函數的編寫可能很難,但是一旦完成,它可以被廣泛地重新使用,而不必擔心錯誤。

這與概念和設計上類似於將foreach循環結構添加到傳統命令式語言中,其思想是您不必自己編寫循環控制(因爲它引入了由一個錯誤導致的機會,增加冗長,在你正在做的每一個條目而不是顯示如何你得到的每個條目什麼方式獲得。高階函數只是讓你的結構的遍歷從該怎麼辦分離,同時穿越可延伸內語言本身。

應當指出的是,在C#中代表們通過lambda表達式在很大程度上取代,因爲編譯器可以簡單地對待它作爲一個更簡潔代表如果想要,但也可以自由穿過表達拉姆達表示到它被傳遞給,以允許願望的(通常是複雜的)重組或重新定位到一些其它結構域的功能比如通過Linq-to-Sql進行數據庫查詢。

c-style函數指針的.net委託模型的一個主要優點是它們實際上是一個元組(兩部分數據)要調用的函數以及函數將被調用的可選對象。這使您可以通過與有關國家這是更強大的功能。由於編譯器可以用它來構建你的背部(1)班的背後,實例化這個類的一個新實例,並把本地變量進入從而使closures

(1)不始終做到這一點,但現在這是一個實現細節