2009-11-14 36 views
15

我在理解C#代表如何工作時遇到了一些麻煩。我有很多代碼示例,但我仍然無法正確掌握它。C代表中的代表#

有人可以用「純英文」向我解釋嗎?當然!代碼示例將有所幫助,但我想我需要更多的描述它的工作方式/原因。

編輯:

好了,問題是:爲什麼代表工作?什麼是整個過程的「流程圖」?

使用代表的先決條件是什麼?

我希望這可以讓問題更清楚。

+1

您能否澄清一下:您是在問如何使用代表,或者您在問C#如何讓委託可能? – Anton 2009-11-14 18:58:52

+0

你的問題不清楚!你能更清楚一點嗎? – 2009-11-14 18:59:57

回答

19

思考委託的一種方法就像是對功能的引用。例如,假設您在窗口中有一個按鈕,並且您希望點擊該按鈕時發生某些事情。您可以將委託附加到按鈕的Click事件,並且每當用戶單擊此按鈕時,您的功能將被執行。

class MyWindow : Window 
{ 
    Button _button; 

    public MyWindow() 
    { 
     _button = new Button(); 
     // place the button in the window 
     _button.Click += MyWindow.ButtonClicked; 
    } 

    static void ButtonClicked(object sender, RoutedEventArgs e) 
    { 
     MessageBox.Show("Button Clicked"); 
    } 
} 

請注意我是如何讓ButtonClicked成爲一個靜態函數 - 接下來我想對非靜態函數做一個說明。假設而不是ButtonClicked是一個非靜態成員:

class MyWindow : Window 
{ 
    Button _button; 
    int _numClicked = 0; 

    public MyWindow() 
    { 
     this._button = new Button(); 
     // place the button in the window 
     this._button.Click += this.ButtonClicked; 
    } 

    void ButtonClicked(object sender, RoutedEventArgs e) 
    { 
     this._numClicked += 1; 
     MessageBox.Show("Button Clicked " + this._numClicked + " times"); 
    } 
} 

現在委託既包含的功能「ButtonClicked」和實例,「這」,該方法被調用的參考。 MyWindow構造函數中的「this」和ButtonClicked中的「this」是相同的。

這是一個被稱爲關閉的特定情況,它允許在創建委託時「保存」狀態 - 當前對象,局部變量等。在上面的例子中,我們使用了委託中構造函數中的「this」。我們可以做更多的事:

class MyWindow : Window 
{ 
    Button _button; 
    int _numClicked = 0; 

    public MyWindow(string localStringParam) 
    { 
     string localStringVar = "a local variable"; 
     this._button = new Button(); 
     // place the button in the window 
     this._button.Click += new RoutedEventHandler(
      delegate(object sender, RoutedEventArgs args) 
      { 
       this._numClicked += 1; 
       MessageBox.Show("Param was: " + localStringParam + 
        " and local var " + localStringVar + 
        " button clicked " + this._numClicked + " times"); 
      }); 
    } 
} 

在這裏,我們創建了一個匿名委託 - 它沒有給出一個明確的名稱的功能。引用此函數的唯一方法是使用RoutedEventHandler委託對象。而且,這個函數存在於MyWindow構造函數的範圍內,因此它可以訪問所有本地參數,變量和成員實例「this」。即使在MyWindow構造函數退出後,它仍將繼續保持對局部變量和參數的引用。

作爲一個方面說明,委託人還將持有對該對象實例的引用 - 「this」 - 即使刪除了所有其他對該類的引用。因此,爲了確保類是垃圾收集,應該刪除所有到非靜態成員方法的委託(或在其範圍內創建的委託)。

+0

所有數據都是有用的和互補的。感謝大家。 我會小心閱讀所有答案並繼續嘗試。再次感謝:D – 2009-11-14 19:55:33

5

那麼,委託是一種類型。委託類型的變量可以引用或指向一個函數。

這給你一個間接的方法來調用一個方法,所以可以在運行時選擇方法。因此,您可以擁有包含方法的變量,參數和屬性。這些屬性稱爲事件。

再多一次的代碼示例,是完整的:

delegate void ADelegate(); // the delegate type 

    void Foo() { ... } // a compatible method 
    void Bar() { ... } // a compatible method 

    void Main() 
    { 
     ADelegate funcPtr; // a delegate variable 

     if (aCondition) 
     funcPtr = Foo; // note: _not_ Foo(), Foo is not executed here 
     else 
     funcPtr = Bar; 

     funcPtr(); // calls Foo or Bar depending on aCondition 
    } 

使用委託變量是不常見的。但是您可以使用委託參數來實例化Sort方法來選擇升序或降序排序。

delegate int Compare(MyClass a, MyClass b); // the delegate type 

    void int CompareUp(MyClass a, MyClass b) { ... } 
    void int CompareDn(MyClass a, MyClass b) { ... } 

    void Sort(MyClass[] data, Compare comparer) { ... } 

而且您可能知道事件,這些事件是基於代表的(特殊類型的)屬性。

2

它是一種倒置原理。通常情況下,您會編寫調用方法的代碼,並且您在編寫代碼時調用的方法是已知的。代表允許您匿名調用方法。那就是你不知道程序運行時調用的實際方法。

它有助於區分應用程序不同部分的問題。所以你可以有一些代碼在數據存儲上執行任務。您可能有其他處理數據的代碼。數據上的進程無需知道數據存儲的結構,數據存儲不應該依賴於數據的使用。

可以寫入處理代碼,以假定某些與數據存儲結構無關的數據。這樣,我們可以更改數據存儲的結構,而不用擔心影響數據上的進程。

2

您可以將委託視爲將代碼視爲數據的方式。如果你創建一個委託,它是一個類型。這種類型的變量可能指向特定的方法(符合委託定義)。

這意味着您可以將一段代碼視爲數據並將其傳遞給方法。由於代表指向代碼(或null),因此您也可以通過變量調用它指向的代碼。

這允許一些非常有用的模式。典型的例子是如何對一個集合進行排序。通過允許調用者提供一個委託來實現對特定元素進行排序的意義,排序方法不需要知道任何有關這方面的信息。

同樣的想法被廣泛用於LINQ的很多方法。即你傳入一個委託(或更常見的lambda)來處理一些特定的任務,並且LINQ方法將會調用它來完成任務。

2

委託是通過委託實例調用單個/多個方法的引用類型。它擁有方法的引用.Delegates可用於處理(調用/調用)單個事件上的多個方法。代表可以用來定義異步方法。 這裏是一個代表的例子 首先我們創建一個類。其中我們聲明瞭delegate.and我們在該類中創建了一個方法來調用委託。

public class simpleinterest 
{ 
    public delegate void intcal(double i); //declare delegate 
    public event intcal interest; //create delegate object 
    public void calculate(double p, double n,double r) 
    { 
     interest(p*n*r/100); //invoke delegate 
    } 

} 

在我們的程序中我們做了映射。那就是我們指定調用委託時觸發哪個事件。

private void btn_Click(object sender, RoutedEventArgs e) 
    { 
     simpleinterest s1 = new simpleinterest(); 
     s1.interest+=new simpleinterest.intcal(s1_interest);//mapping 

     s1.calculate(1000,3,10); 

    } 
    void s1_interest(double r) 
    { 
     MessageBox.Show("Amount:" + r.ToString()); 

    } 
4

委託是函數指針到某處定義的方法。

假設你有一個的BankAccount類,你必須發送電子郵件給客戶,只要他/她的餘額小於$ 100。然後,自然的趨勢是在餘額屬性設置器中添加一個支票,以查看客戶的餘額是否低於100美元,如果是,則觸發電子郵件。但是這種設計並不靈活。上述辦法的

缺點:

將來,肯定會以發送短信而不是電子郵件的客戶的要求。很少有客戶選擇電子郵件和短信。因此,無論何時您需要通知客戶有任何更改,您都會去修改BankAccount類。這是違反的開放式擴展和關閉修改堅實的設計原則。

替代使用溶液代表們的:

  1. 定義NotifyCustomer()方法,其與發送通知客戶有關低平衡,的BankAccount類以外的交易。

  2. 修改BankAccount類來定義委託並在構造函數中接受它的值。

  3. 在創建的BankAccount類,通過在步驟1中

  4. 在的BankAccount的類餘額設置器創建的NotifyCustomer()方法,檢查是否餘額小於$ 100。如果是這樣,請調用委託。

  5. 的BankAccount類外定義的NotifyCustomer()方法被調用,導致發送所定義的通知。

在未來,如果有通知客戶的一種新的方式,那麼不需要改變在的BankAccount類。使用委託設計的

優點:

  1. 鬆耦合:本的BankAccount類不知道的硬編碼邏輯通知客戶。

  2. 遵循改性原理對擴展開放和關閉:無論何時,你並不需要通知客戶變化的介質改變的BankAccount類。所以現在你會很自豪地說你的BankAccount類設計遵循設計原則。

如果您想了解更多關於委託的一個例子,讀What are delegates and why we need them.

1

委託是引用類型,委託是指方法。這被稱爲封裝方法。當您創建一個委託時,您可以指定一個方法簽名和返回類型。您可以使用該委託封裝任何匹配的方法。創建與委託關鍵字的委託,然後返回類型和可轉授的方法的簽名,如下所示:

public delegate void HelloFunctionDelegate(string message); 
class Program 
{ 
static void Main() 
{ 
HelloFunctionDelegate del = new HelloFunctionDelegate(Hello); 
del("Hello from Delegate"); 
} 
public static void Hello(string strMessage) 
{ 
Console.WriteLine(strMessage); 
} 
} 

輸出是爲你好,從代表

0

Delegate是一個引用類型變量,它指向方法的引用。所有委託都來自System.Delegate類。例如,在Windows窗體或WPF中,方法事件與代理的概念一起工作。 這是在c#使用delagates在C#Introduction to delegates in C#

1

Delagates的例子:它定義該方法的其它可invoke.In換句話說,我們可以說,它包裝的方法的參考簽名它可以呼叫。 下面是代表用途:

  1. 它提供了實現回調在.NET框架功能的機制。
  2. 它提供了按順序調用多個方法的功能。
  3. 它有能力實現異步方法調用。

它支持靜態方法和實例方法。

下面是它在內部的工作原理。

//下面是代表的聲明。

public delegate void DisplayNamme(string name); 

運行時CLR爲代表創建一個類,如下所示。

public class DisplayNamme : System.MulticastDelegate{ 

    // It is a contructor 
    public DisplayNamme(Object @object, IntPtr method); 

    // It is the method with the same prototype as defined in the source code. 
    public void Invoke(String name); 

// This method allowing the callback to be asynchronouslly. 

public virtual IAsyncResult BeginInvoke(String name, 
AsyncCallback callback, Object @object); 

public virtual void EndInvoke(IAsyncResult result); 

} 

我們可以看到它通過程序Ildasm.exe工具使用此工具可以中斷DLL。

構造函數有兩個參數:IntPrt引用傳遞給函數的方法的名稱,而@object引用隱式傳遞給構造函數的對象的引用。

CLR使用委託的Invoke方法來調用回調方法。

下面是使用委託的回調方法的實現。

// Declare Delegates 
    public delegate void DisplayNamme(string name); 
    class Program 
    { 
     public static void getName(string name) 
     { 
      Console.WriteLine(name); 
     } 
     public static void ShowName(DisplayNamme dn, string name) 
     { 
     // callback method calling. We can call it in two ways. 
      dn(name); 
      // or explicitly 
      dn.Invoke(name); 
    } 
     static void Main(string[] args) 
     { 
      DisplayNamme delDN = getName; 
      Program.ShowName(delDN, "CallBack"); 
      Console.ReadLine(); 
     } 
    } 
1

1)首先你要明白爲什麼/當你需要一個代表,什麼是它解決的問題。

以我的經驗我主要用它們來允許用戶自定義一個對象的行爲

Immagine a Grid組件允許開發人員定製每列的渲染方式。 例如,如果您想在紅色值爲零以下時寫入紅色值。

創建網格的開發人員不知道用戶如何定製輸出,因此它需要一種機制讓組件的用戶將某些邏輯注入組件

2)然後,你必須要了解的委託是如何工作的

什麼是混淆是你必須寫這樣做奇怪代碼,你必須做同樣的許多方面事情。

這是網格類:

// the grid let the programmer that will use it to customize the output 
public class Grid{ 

    // 1) First I declare only the interface of the delegate 
    public delegate String ValueFormatterDelegate(String v); 

    // 2) I declare a handler of the implementation of the delegate 
    public ValueFormatterDelegate ValueFormatterHandler; 

    // 3) I call the handler inside the Print method 
    public void Print(String x){ 
     Console.WriteLine(ValueFormatterHandler.Invoke(x)); 
    } 

} 

// 1)首先我聲明僅委託 公共代表字符串ValueFormatterDelegate(字符串V)的接口;

注意,是像一個正常的方法,但是:

  • 它具有委託關鍵字
  • 它不具有實現

這樣我說:「格式化輸出的方法有這個接口:它將採取一個字符串作爲輸入,它會輸出一個字符串」

它記得我接口方法的定義。

// 2)本人聲明委託 公共ValueFormatterDelegate ValueFormatterHandler執行的處理程序;

現在我必須創建一個委託類型的屬性來處理此方法的實現。

// 3)I調用打印方法 公共無效打印(串x){Console.WriteLine (ValueFormatterHandler內的處理程序。調用(x)); }

在打印方法中,我可以使用處理程序,它將鏈接真正的實現。

ValueFormatterHandler的類型是ValueFormatterDelegate 和ValueFormatterDelegate是廣告代理 和.Invoke是委託類型

的方法,這是用我的網類,並且是能夠將其在飛行個性化的程序。 這裏的問題是你需要做很多事情。

using System; 

public class Program{ 
    public static void Main(){ 

     var printer = new Printer(); 

     // METHOD 1 : link to a named method 
     // here i link the handler of the delegate to a real method 
     // the FormatXXX is a static method defined at the ed of this code 
     printer.ValueFormatter = FormatXXX; 

     // when i call Print("hello") 
     printer.Print("hello"); // XXhelloXX 

     // METHOD 2 : anonimous method 
     // think at this like a method but without a name 
     // FormatYY (String x){ return "YY"+x+"YY"; }; 
     // become 
     // delegate (String x){ return "YY"+x+"YY"; }; 
     printer.ValueFormatter = delegate (String x){ return "YY"+x+"YY"; }; 
     printer.Print("hello"); // YYhelloYY 

     // METHOD 3 : anonimous method using lambda 
     // as you can note the type of parameter x is inferred from the delegate declaration 
     // public delegate String ValueFormatterDelegate(String v); 
     printer.ValueFormatter = (x)=>"KK" + x + "KK"; 

    } 

    public static String FormatXXX(String y){ 
     return "XX"+ y +"XX"; 
    } 

}