博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
温故而知新:Delegate,Action,Func,匿名方法,匿名委托,事件
阅读量:5364 次
发布时间:2019-06-15

本文共 6282 字,大约阅读时间需要 20 分钟。

一、委托Delegate

一般的方法(Method)中,我们的参数总是string,int,DateTime...这些基本的数据类型(或者没有参数),比如

public
 
void
 HelloWorld() 
{
    Console.WriteLine(
"
Hello World!
"
);
}
public
 
void
 HelloWorld(
string
 name) 
{
    Console.WriteLine(
"
Hello ,{0}!
"
, name);
}

但是有些时候,我们希望把一个方法本身当做参数传递给另一个方法,比如

myObject.callMethod(HelloWorld);

在没有委托之前,这是一件极困难的事情,委托出现以后,这就是一件很容易的事情了,简单点讲:委托就是一种能把方法当做参数来使用的类型--当然这个定义跟官方的解释比起来极不严密,但易于理解

要点:

1.委托是一种类型(跟string,int,double...一样是.net的一种基本类型)
2.委托的定义必须与最终被调用的方法保持签名一致

比如:下面代码中的

delegate void D1(); 与 static void HelloWorld1(),我们抛开前面的类型关键字delegate与static,他们的签名都是void X()

void D2(string myName);与void HelloWorld2(string name); void HelloWorld3(string name);它们的签名格式都是 void X(string Y)

3.委托的好处之一在于可以保持签名格式不变的情况下,动态调用不同的处理逻辑(即不同的方法)

想想系统控件中的Button类,系统并不知道按钮按下去时到底会执行怎么样的逻辑(点击后的处理,每个项目可能都不一样,完全由需求决定),但是我们知道每个Button都有一个Click(object sender, EventArgs e)这样的东东,没错,就是委托(当然封装成了另一种衍生类型event),就是这种设计保证了统一的格式,不管你实际开发中想如何处理点击后的逻辑,只要按这个统一的签名来就行了

完整代码演示:

using
 System;
namespace
 ActionStudy
{
    
class
 Program
    {
       
        
delegate
 
void
 D1();
        
delegate
 
void
 D2(
string
 myName);
        
static
 
void
 Main(
string
[] args)
        {
            D1 d1 
=
 
new
 D1(HelloWorld1);
            d1();
            D2 d2 
=
 
new
 D2(HelloWorld2);
            d2(
"
Jimmy
"
);
            d2 
=
 
new
 D2(HelloWorld3);
            d2(
"
杨俊明
"
);            
            Console.Read();
        }
        
static
 
void
 HelloWorld1()
        {
            Console.WriteLine(
"
Hello World!
"
);
        }
        
static
 
void
 HelloWorld2(
string
 name) 
        {
            Console.WriteLine(
"
Hello,{0}!
"
, name);
        }
        
static
 
void
 HelloWorld3(
string
 name)
        {
            Console.WriteLine(
"
你好,{0}!
"
, name);
        }
    }
}

 二 、匿名方法(.net2.0开始支持)

在“一、委托Delegate”的演示代码中,我们看到委托调用方法前,至少得先定义一个签名相同的方法,然后才能由委托调用(哪怕是只有一行代码的方法),好象有点烦哦,想偷懒,ok,没问题

using
 System;
namespace
 ActionStudy
{
    
class
 Program
    {
        
delegate
 
void
 D1();
        
delegate
 
void
 D2(
string
 myName);
        
static
 
void
 Main(
string
[] args)
        {
            D1 d1 
=
 
delegate
            {
                Console.WriteLine(
"
Hello World!
"
);
            };
            d1();
            D2 d2 
=
 
delegate
(
string
 name)
            {
                Console.WriteLine(
"
Hello,{0}!
"
, name);
            };
            d2(
"
Jimmy
"
);
            d2 
=
 
delegate
(
string
 name)
            {
                Console.WriteLine(
"
你好,{0}!
"
, name);
            };
            d2(
"
杨俊明
"
);
            Console.Read();
        }
    }
}

运行效果完全相同,只是省去了方法的单独定义部分

到了.net 3.0这种偷懒的作风更夸张,看下面的代码(利用了Lambda表达式)

using
 System;
namespace
 ActionStudy
{
    
class
 Program
    {
        
delegate
 
void
 D1();
        
delegate
 
void
 D2(
string
 myName);
        
static
 
void
 Main(
string
[] args)
        {           
            D1 d1 
=
 () 
=>
 { Console.WriteLine(
"
Hello World!
"
); };
            d1();
            D2 d2 
=
 (
string
 name) 
=>
 { Console.WriteLine(
"
Hello,{0}!
"
, name); };
            d2(
"
Jimmy
"
);
            d2 
=
 (
string
 name) 
=>
 { Console.WriteLine(
"
你好,{0}!
"
, name); };
            d2(
"
杨俊明
"
);
            Console.Read();
        }
    }
}

运行效果仍然没变,初次接触者可能感觉很怪,其实我也觉得怪,不过很多大牛们都喜欢这样用,所以至少还是要能看得懂,否则别人会说"你 Out了" :)

三、Action

Action的本质就是委托,看它的定义:

namespace
 System
{
    
//
 摘要:
    
//
     Encapsulates a method that takes no parameters and does not return a value.
    
public
 
delegate
 
void
 Action();
}
namespace
 System
{
    
//
 摘要:
    
//
     Encapsulates a method that takes a single parameter and does not return a
    
//
     value.
    
//
    
//
 参数:
    
//
   obj:
    
//
     The parameter of the method that this delegate encapsulates.
    
//
    
//
 类型参数:
    
//
   T:
    
//
     The type of the parameter of the method that this delegate encapsulates.
    
public
 
delegate
 
void
 Action
<
T
>
(T obj);
}

 当然,还有Action<T1,T2>乃至Action<T1,T2,T3,T4>参数个数从2到4的类型,不过定义都差不多

简单点讲,Action是参数从0到4,返回类型为void(即没有返回值)的委托

using
 System;
namespace
 ActionStudy
{
    
class
 Program
    {
        
static
 Action A1;
        
static
 Action
<
string
>
 A2;
       
        
static
 
void
 Main(
string
[] args)
        {
            A1 
=
 
new
 Action(HelloWorld1);
            A1();
            A2 
=
 
new
 Action
<
string
>
(HelloWorld2);
            A2(
"
Jimmy
"
);
            A2 
=
 (
string
 name) 
=>
 { Console.WriteLine(
"
你好,{0}!
"
, name); };
            A2(
"
杨俊明
"
);
            A2 
=
 
delegate
(
string
 name) { Console.WriteLine(
"
我就是委托,{0} 你说对吗?
"
, name); };
            A2(
"
菩提树下的杨过
"
);          
            Console.Read();
        }
        
static
 
void
 HelloWorld1()
        {
            Console.WriteLine(
"
Hello World!
"
);
        }
        
static
 
void
 HelloWorld2(
string
 name)
        {
            Console.WriteLine(
"
Hello,{0}!
"
, name);
        }
       
    }
   
}

四、Func

Func其实也是一个"托"儿,呵呵,不过这个委托是有返回值的。看下定义就知道了:

namespace
 System
{
    
//
 摘要:
    
//
     Encapsulates a method that has no parameters and returns a value of the type
    
//
     specified by the TResult parameter.
    
//
    
//
 类型参数:
    
//
   TResult:
    
//
     The type of the return value of the method that this delegate encapsulates.
    
//
    
//
 返回结果:
    
//
     The return value of the method that this delegate encapsulates.
    
public
 
delegate
 TResult Func
<
TResult
>
();
}
namespace
 System
{
    
//
 摘要:
    
//
     Encapsulates a method that has one parameter and returns a value of the type
    
//
     specified by the TResult parameter.
    
//
    
//
 参数:
    
//
   arg:
    
//
     The parameter of the method that this delegate encapsulates.
    
//
    
//
 类型参数:
    
//
   T:
    
//
     The type of the parameter of the method that this delegate encapsulates.
    
//
    
//
   TResult:
    
//
     The type of the return value of the method that this delegate encapsulates.
    
//
    
//
 返回结果:
    
//
     The return value of the method that this delegate encapsulates.
    
public
 
delegate
 TResult Func
<
T, TResult
>
(T arg);
}

同Action类似,Func的参数从1到5个,有5个不同的重载版本

代码:

using
 System;
namespace
 ActionStudy
{
    
class
 Program
    {
                
        
static
 Func
<
string
>
 F;
        
static
 Func
<
DateTime, 
string
>
 F2;      
        
static
 
void
 Main(
string
[] args)
        {
            F 
=
 
new
 Func
<
string
>
(HelloWorld1);
            Console.WriteLine(F());
            F2 
=
 
new
 Func
<
DateTime, 
string
>
(HelloWorld2);
            Console.WriteLine(F2(DateTime.Now));
            Console.Read();
        }
        
static
 
string
 HelloWorld1()
        {
            
return
 
"
Hello World!
"
;
        }
        
static
 
string
 HelloWorld2(DateTime time)
        {
            
return
 
string
.Format(
"
Hello World,the time is {0}.
"
, time);
        }
       
    }   
}

五、匿名委托

ok,如果你没有晕的话,再来看一下匿名委托,其实这也是一种偷懒的小伎俩而已

看代码说话:

//F = new Func<string>(HelloWorld1);

其实也可以简写成这样:

F = HelloWorld1;          

//F2 = new Func<DateTime, string>(HelloWorld2);

其实也可以简写成这样

F2 = HelloWorld2;

方法直接赋值给委托,这二个类型不同吧???

没错,你会发现编译一样能通过,系统在编译时在背后自动帮我们加上了类似 “= new Func<...>”的东东,所以我们能偷懒一下下,这个就是匿名委托。

如果你细心的话,会发现我们在定义Button的Click处理事件时,通常是这样的:

this.button1.Click += new EventHandler(button1_Click);

但有时候我们也可以写成这样:

this.button1.Click += button1_Click;

这其实就是匿名委托的应用. 

六、事件event

其实,这...还是个托儿!

我们来看下按钮Click事件的定义

//
 摘要:
//
     Occurs when the control is clicked.
public
 
event
 EventHandler Click;

继续刨根问底,查看EventHandler的定义: 

using
 System.Runtime.InteropServices;
namespace
 System
{
    
//
 摘要:
    
//
     Represents the method that will handle an event that has no event data.
    
//
    
//
 参数:
    
//
   sender:
    
//
     The source of the event.
    
//
    
//
   e:
    
//
     An System.EventArgs that contains no event data.
    [Serializable]
    [ComVisible(
true
)]
    
public
 
delegate
 
void
 EventHandler(
object
 sender, EventArgs e);
}

 

看到了吧,就是委托!

转载请注明来自菩提树下的杨过

 

转载于:https://www.cnblogs.com/anorthwolf/archive/2010/04/06/1705658.html

你可能感兴趣的文章
js函数中this的指向
查看>>
c++ 引用方式传递数组
查看>>
HBase学习之路 (九)HBase phoenix的使用
查看>>
LeetCode() Remove Duplicates from Sorted Array II
查看>>
【svn】idea svn 文件上会出现一个破书
查看>>
cocos2d-x 3.0 场景切换特效汇总(转)
查看>>
The SortedMap Interface
查看>>
SniperOJ-leak-x86-64
查看>>
bzoj 4260: Codechef REBXOR (01 Trie)
查看>>
学好python
查看>>
css-IE中的border-radius和box-shadow
查看>>
利用bootstrap和webform的异步CRUD及分页
查看>>
HDUOJ 1879继续畅通工程(并查集)
查看>>
OC12_自动释放池
查看>>
Saiku资源帖
查看>>
解决手机页面中点击文本框,网页放大问题
查看>>
2-5
查看>>
牛客多校3 A-PACM Team(状压降维+路径背包)
查看>>
HDU - 4284 Travel(floyd+状压dp)
查看>>
1027 制作表格
查看>>