• C# 委托Delegate


    委托


     

    C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。

    委托(Delegate)特别用于实现事件和回调方法。所有的委托(Delegate)都派生自 System.Delegate 类。

    声明委托(Delegate)

    委托声明决定了可由该委托引用的方法。委托可指向一个与其具有相同标签的方法。

     

    1 delegate 函数返回类型 委托名 (<方法参数列表>);

    实例化委托(Delegate)

    委托对象必须使用 new 关键字来创建,且与一个特定的方法有关。当创建委托时,传递到 new 语句的参数就像方法调用一样书写,但是不带有参数。

    1 委托类型 实例名 = new 委托类型 (<注册方法>);

    通过委托实例来调用方法,执行委托实例就等同于执行注册方法。

    匿名函数初始化委托

    为初始化委托而专门定义方法较为麻烦,通常调用委托实例初始化时赋值的方法,而不直接调用方法本身。

     格式如下:

    1 delegate 委托(函数)返回类型 委托类型(函数参数列表);
    2 
    3 委托类型 委托实例= new 委托类型(delegate(<函数参数列表:类型 形参名,类型 形参名...>)
    4 {
    5     //函数体
    6 });

    或者省去new关键字。

    1 delegate 委托(函数)返回类型 委托类型(函数参数列表);
    2 
    3 委托类型 委托实例= delegate(<函数参数列表:类型 形参名,类型 形参名...>)
    4 {
    5     //函数体
    6 };

     

    委托的多播(Multicasting of a Delegate)

    委托对象可使用 "+" 运算符进行合并。一个合并委托调用它所合并的两个委托。只有相同类型的委托可被合并。"-" 运算符可用于从合并的委托中移除组件委托。

    使用委托的这个有用的特点,您可以创建一个委托被调用时要调用的方法的调用列表。这被称为委托的 多播(multicasting),也叫组播。

    利用多播可以将委托中的函数类似数据一样扩展或消减。

     1 namespace _9_delegate_2_20170801
     2 {
     3     class TestDelegate
     4     {
     5         public static void PrintfA()
     6         {
     7             Console.WriteLine("PrintfA !");
     8         }
     9 
    10         public static void PrintfB()
    11         {
    12             Console.WriteLine("PrintfB !");
    13         }
    14     }
    15     delegate void Mydelegate();
    16 
    17     class Program
    18     {
    19         static void Main(string[] args)
    20         {
    21             // 创建委托实例
    22             Mydelegate d;
    23             Mydelegate da = new Mydelegate(TestDelegate.PrintfA);
    24             Mydelegate db = new Mydelegate(TestDelegate.PrintfB);
    25             d = da;
    26             d += db;
    27             // 调用多播
    28             Console.WriteLine("调用委托实例d ==da+db:");
    29             d();
    30             d -= da;
    31             Console.WriteLine("调用委托实例d ==db:");
    32             d();
    33         }
    34     }
    35 }
    委托多播例子


    委托的好处


    1、操作函数更加灵活,就像使用变量一样方便,具有动态性,可避免程序中大量的使用分支语句。

    2、与C++,C中的函数指针相比,委托是面向对象、类型安全、可靠的受控对象。委托能保证指向一个安全有效不会越界的储存函数的地址。

    3、与C++,C中的函数指针相比,指针只能指向静态函数,委托可以引用静态函数也可以引用非静态成员函数

    当程序必须调用一个方法来执行某个操作,但编译无法确定是什么方法时,就可以使用委托。

     

     Action委托和Func委托


    除了我们自己定义的委托之外,系统还给我们提供过来一个内置的委托类型,Action和Func。

    Action委托引用了一个void返回类型的方法,T表示方法参数。

    Action<参数类型列表> Action委托实例 = 方法签名;

    Func引用了一个带有一个返回值的方法,它可以传递0或者多到16个参数类型,和一个返回类型

    Func<参数类型列表,返回类型> Func实例名 = 方法签名;

     在调用时,Func类委托和Action类委托都一样:

    实例名(参数);

    一个Action委托的使用例子:

     1 class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             Action<int, string> eatAction = Eat;
     6             eatAction(5, "苹果");
     7             Action<int, string> palceAction = Place;
     8             palceAction(10, "香蕉");
     9 
    10             Action<int, string> doAction;
    11             doAction = eatAction;
    12             doAction += palceAction;
    13             doAction(8,"西瓜");
    14         }
    15         private static void Eat(int num, string name)
    16         {
    17             Console.WriteLine($"我吃了{num}个{name}");
    18         }
    19         private static void Place(int num, string name)
    20         {
    21             Console.WriteLine($"我放了{num}个{name}");
    22         }
    23     }
    Action委托例子

    Lambda表达式


    从C#3.0开始,可以使用Lambda表达式代替匿名方法。只要有委托参数类型的地方就可以使用Lambda表达式。Lamdba表达式方便了委托的。

    通过一个例子:

     1 class Program
     2     {
     3         delegate string PrintfInfo(string name, string dowhat);
     4         static void Main(string[] args)
     5         {
     6             //不用Lambda表达式的Func-------
     7             Func<int, int, int> plus = delegate(int arg1, int arg2)
     8             {
     9                 return arg1 + arg2;
    10             };
    11             
    12             //用Lambda表达式的Action--------
    13             Action<int, int> printf = (arg1, arg2) =>  Console.WriteLine($"输入的数{arg1},{arg2}"); 
    14             
    15             //用Lambdab表达式的一般委托
    16             PrintfInfo printfInfo = (name, dowhat) =>
    17             {
    18                 string s = name + "想去" + dowhat;
    19                 return s;
    20             };
    21 
    22 
    23             Console.WriteLine(plus(99, 1));//输出Func
    24             printf(99, 1);//输出Action
    25             Console.WriteLine(printfInfo("小明","吃KFC"));//输出delegate
    26         }
    27     }
    Lambda的使用例子

    可以总结出来:

     委托的使用格式一般为:

    委托类型 委托实例名  =  ( 参数名列表 A, B , C )  =>  {  函数体  } 

    需要注意:

    “=”和“=>”无法省略,“()”和“{}”在特殊情况可以省略,比如:

    1 Action<int> printf =a=>  Console.WriteLine($"输入的数:{a}"); //一个参数且一行代码的函数体
    2 Action printf =()=>  Console.WriteLine($"输入的数:{a}"); //无参数且一行代码的函数体

    通过Lambda表达式可以访问Lambda表达式块外部的变量。这是一个非常好的功能,但如果不能正确使用,也会非常危险。

    示例:

    1 int somVal = 5;
    2 
    3 Func<int,int> f = x=>x+somVal;
    4 
    5 Console.WriteLine(f(3));//8
    6 
    7 somVal = 7;
    8 
    9 Console.WriteLine(f(3));//10

    这个方法的结果,不但受到参数的控制,还受到somVal变量的控制,结果不可控,容易出现编程问题,用的时候要谨慎。

    事件


    事件(event)基于委托,为委托提供了一个发布/订阅机制,我们可以说事件是一种具有特殊签名的委托。

    什么是事件?事件(Event)是类或对象向其他类或对象通知发生的事情的一种特殊签名的委托.

    事件的声明

    public event 委托类型 事件名;

    事件使用event关键词来声明,他的返回类值是一个委托类型。

    通常事件的命名,以名字+Event 作为他的名称,在编码中尽量使用规范命名,增加代码可读性。

     

  • 相关阅读:
    传说中的灵感
    错误: Sys.WebForms.PageRequestManagerServerErrorException: 只能在执行 Render() 的过程中调用 RegisterForEventValidation;
    只能在执行 Render() 的过程中调用 RegisterForEventValidation
    在aspx实现用户控件内Web控件的事件
    Asp.net网页上嵌入Media Player播放
    为临时表动态添加字段
    如何防止头文件被重复包含、嵌套包含
    Linux C SQLite3 编程
    Android开源项目源码下载(不断更新中)
    Android程序员必看之Android六大优势
  • 原文地址:https://www.cnblogs.com/craft0625/p/7266474.html
Copyright © 2020-2023  润新知