📜  C#|代表们

📅  最后修改于: 2021-05-29 22:41:31             🧑  作者: Mango

委托是引用方法的对象,或者可以说它是可以保存对方法的引用的引用类型变量。 C#中的委托类似于C / C++中的函数指针。它提供了一种方法,该方法告诉事件触发时将调用哪个方法。
例如,如果您单击窗体(Windows窗体应用程序)上的“按钮”,则程序将调用特定的方法。简而言之,它是一种类型,它表示对具有特定参数列表和返回类型的方法的引用,然后在程序中调用该方法以在需要时执行。

关于代表的要点:

  • 提供了封装方法的好方法。
  • 委托是系统名称空间中的库类。
  • 这些是任何方法的类型安全指针。
  • 委托主要用于实现回调方法和事件。
  • 可以将委托链接在一起,因为可以在单个事件上调用两个或多个方法。
  • 它不在乎它引用的对象的类。
  • 委托也可以用于“匿名方法”调用中。
  • 匿名方法(C#2.0)和Lambda表达式(C#3.0)被编译为在某些上下文中委派类型。有时,这些功能一起被称为匿名功能。

代表宣言

可以使用委托关键字声明委托类型。声明委托后,委托实例将引用并调用其返回类型和参数列表与委托声明匹配的方法。

句法:

[modifier] delegate [return_type] [delegate_name] ([parameter_list]);

例子:

// "public" is the modifier
// "int" is return type
// "GeeksForGeeks" is delegate name
// "(int G, int F, int G)" are the parameters
public delegate int GeeksForGeeks(int G, int F, int G);

注意:委托将仅调用与其签名和返回类型一致的方法。方法可以是与类关联的静态方法,也可以是与对象关联的实例方法,这无关紧要。

代表的实例化和调用

声明委托后,将在new关键字的帮助下创建一个委托对象。实例化委托后,委托对该委托进行的方法调用将传递给该方法。调用者传递给委托的参数将传递给方法,委托返回给方法的返回值(如果有)。这称为调用委托。

句法:

[delegate_name]  [instance_name] = new [delegate_name](calling_method_name);

例子:

GeeksForGeeks GFG = new GeeksForGeeks (Geeks);
       // here,
       // "GeeksForGeeks" is delegate name. 
       // "GFG" is instance_name
       // "Geeks" is the calling method.

下面的程序说明了Delegate的用法:

// C# program to illustrate the use of Delegates
using System;
namespace GeeksForGeeks {
      
// declare class "Geeks"
class Geeks {
      
// Declaring the delegates
// Here return type and parameter type should 
// be same as the return type and parameter type
// of the two methods
// "addnum" and "subnum" are two delegate names
public delegate void addnum(int a, int b);
public delegate void subnum(int a, int b);
      
    // method "sum"
    public void sum(int a, int b)
    {
        Console.WriteLine("(100 + 40) = {0}", a + b);
    }
  
    // method "subtract"
    public void subtract(int a, int b)
    {
        Console.WriteLine("(100 - 60) = {0}", a - b);
    }
  
// Main Method
public static void Main(String []args)
{
      
    // creating object "obj" of class "Geeks"
    Geeks obj = new Geeks();
  
    // creating object of delegate, name as "del_obj1" 
    // for method "sum" and "del_obj2" for method "subtract" &
    // pass the parameter as the two methods by class object "obj"
    // instantiating the delegates
    addnum del_obj1 = new addnum(obj.sum);
    subnum del_obj2 = new subnum(obj.subtract);
  
    // pass the values to the methods by delegate object
    del_obj1(100, 40);
    del_obj2(100, 60);
  
    // These can be written as using
    // "Invoke" method
    // del_obj1.Invoke(100, 40);
    // del_obj2.Invoke(100, 60);
}
}
}

输出:

(100 + 40) = 140
(100 - 60) = 40

说明:在上面的程序中,有两个委托addnumsubnum 。我们正在创建Geeks类的对象obj ,因为这两个方法( addnumsubnum )都是实例方法。因此,他们需要一个对象来调用。如果方法是静态的,则无需创建类的对象。

委托的多播

委托的多播是普通委托(有时称为“单播委托”)的扩展。它可以帮助用户在单个调用中指向多个方法。

特性:

  • 委托被组合在一起,当您调用委托时,将调用完整的方法列表。
  • 所有方法均以先进先出(FIFO)的顺序调用。
  • ‘+’或’+ =’运算符用于将方法添加到委托中。
  • “ –”或“-=”运算符用于从委托列表中删除方法。

注意:请记住,委托的多播应具有Void的返回类型,否则它将引发运行时异常。同样,委托的多播将仅从多播中添加的最后一个方法返回值。虽然,其他方法将成功执行。

下面的程序演示了委托多播的用法:

// C# program to illustrate the 
// Multicasting of Delegates
using System;
  
class rectangle {
      
// declaring delegate
public delegate void rectDelegate(double height,
                                  double width);
  
    // "area" method
    public void area(double height, double width)
    {
        Console.WriteLine("Area is: {0}", (width * height));
    }
   
    // "perimeter" method
    public void perimeter(double height, double width)
    {
        Console.WriteLine("Perimeter is: {0} ", 2 * (width + height));
    }
   
   
// Main Method
public static void Main(String []args)
{
      
    // creating object of class 
    // "rectangle", named as "rect"
    rectangle rect = new rectangle();
  
    // these two lines are normal calling
    // of that two methods
    // rect.area(6.3, 4.2);
    // rect.perimeter(6.3, 4.2);
  
    // creating delegate object, name as "rectdele"
    // and pass the method as parameter by 
    // class object "rect"
    rectDelegate rectdele = new rectDelegate(rect.area);
      
    // also can be written as 
    // rectDelegate rectdele = rect.area;
  
    // call 2nd method "perimeter"
    // Multicasting
    rectdele += rect.perimeter; 
  
    // pass the values in two method 
    // by using "Invoke" method
    rectdele.Invoke(6.3, 4.2);
    Console.WriteLine();
      
    // call the methods with 
    // different values
    rectdele.Invoke(16.3, 10.3);
}
}

输出:

Area is: 26.46
Perimeter is: 21 

Area is: 167.89
Perimeter is: 53.2