C#中委托如何使用?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#中委托如何使用?相关的知识,希望对你有一定的参考价值。

C#中委托如何使用?

谢谢大家
详细一点

1.委托概述
委托是C#中新加入的一个类型,可以把它想作一个和Class类似的一种类型,和使用类相似,使用一个委托时,需要两个步骤,首先你要定义一个委托,就像是定义一个类一样;然后,你可以创建一个或多个该委托的实例。
定义一个委托的语法是这样的:
[public/protected/private] delegate returnType delegateName(paramtype param1,…)
这是我自己写的,看起来好像有点怪怪的,我来解释一下,private/protected/private是限定词,就不多说了,delegate是申明一个委托的关键词,returnType是一个返回类型,delegateName是一个你给委托起的名字,你可以写任何一个你喜欢的名字,paramtype param1…这个是参数列表。说了这么多可能看起来还是不是很好理解,我是这样认为的,实用点来讲,委托定义就是在一个函数定义中间加入一个delegate的关键词。它的作用类似于你申明一个类:
public class ClassName …
创建一个委托的实例:
[public/protected/private] delegateName deleInstanceName = new delegateName(MethodName)
这个类似于实例化一个类,public ClassName instancename = new ClassName(…),这里有个要注意的地方,即MethodName方法要和delegateName的签名一致。什么是签名一致,就是说MethodName的参数列表,返回值要分别和returnType、(paramtype param1,…)一致。举个例子来说明下:
public delegate string DelegateDemo(string name, int age);
比如我们如上定义了一个委托,就写法来说,其实就是在函数 string DelegateDemo(string name, int age)前面加了一个delegate的关键字,下面我们来用创建一个函数:
public string AgentDemo(string name, int age)

string rev = “”;

return rev;

这个函数是做参数传递给一个DelegateDemo实例的,接下来创建一个DelegateDemo的实例:
DelegateName instanceDemo = new DelegateName(AgentDemo);
这时要说到一致了,即AgentDemo和声明委托时的DelegateDemo(我们姑且将delegate去掉)这两个函数的返回值,参数列表要相同。终于说完了,不知道看的人明不明白。
接下来,我们可以使用这个委托了(调用一个委托),如下:
string name = “cshape”;
int age = 20;
instanceDemo(name, age);
当instanceDemo执行时,会执行AgentDemo函数,instanceDemo相当于C里的一个函数指针,现在这个指针指向AgentDemo的函数入口地址。
2.多点委托
前面提到的委托都只包含对一个方法的调用,如果需要调用多个方法,需要多次显示的调用这个委托,我们还有另的选择,我们可以让一个委托中包含多个方法,这样我们一次显示调用委托,就可以按照顺序连续的调用多个方法。看下面的例子:
public delegate void MultiDelegate(string name);
public void AgentDemo1(string str)

Console.WriteLine(str + “this is AgentDemo1\n”);


public void AgentDemo2(string s)

Console.WriteLine(s + “this is AgentDemo2\n”);


MultiDelegate multiDemo = new MultiDelegate(AgentDemo1);
multiDemo += new MultiDelegate(AgentDemo2);
multiDemo(“multiDemo test :”);

输出的结果应该是:
multiDemo test :this is AgentDemo1
mutliDemo test :this is AgentDemo2

可以看到我们一次显示的调用一个委托,它顺序的(按照你添加方法的顺序)执行了方法AgentDemo1和AgentDemo2。这里要注意的有几点:
● 委托支持 +=,-=这样的运算符,对应为添加或去掉一个方法
● 多点委托不可以定义有返回值,因为无法处理多个方法的返回值,所以如果要使用多点委托,应该用void,否则你的编译会返回一个错误
● 多点委托不建议你的参数列表中有OUT的类型,这样只会out最后一个方法的值,其他的值会丢失。
3.委托的理解
首先申明,这只是我举的一个例子,目的是帮助理解委托的过程,其中很多地方都经不起推敲,望大家知悉。言归正传,
你想要吃饭,
但是自己又不会做(委托方不知道实现细节),
你计划找个饭店,叫个回锅肉饭(定义了一个委托)
你决定找常去的那家叫做A的饭店(实例化一个委托)
你打电话给A饭店(委托调用)
A饭店给你做好了你的回锅肉饭(代理函数工作)
饭来了,真好。

4.委托的使用时机
当你需要把一个方法传送给其他方法时,可以考虑使用委托。好像不是很好理解,也可以这样说,当你确定要处理一件事,但又不能确定处理方法时,可以考虑用委托。其实单独的说委托的应用好像有点牵强,委托更多的是在事件中的应用。
5.一个委托的例子
我用两个类来做这个例子,一个类,我称它为委托方,一个类我称它为代理方,代码如下:
using System;

namespace Visen.Demo.Delegate

///<summary>
/// StartUp 委托演示中的程序入口,含委托方。
///</summary>
class StartUp

#region公用的方法

#region应用程序的主入口点。
///<summary>
///应用程序的主入口点。
///</summary>
[STAThread]
static void Main(string[] args)

Console.WriteLine("This is a delegate demo\n");

Visen.Demo.Delegate.Agent ag = new Agent();

//定义一个委托类型的对象
OutMessage singleDele = new OutMessage(ag.ShowMessage);
OutMessage deleStaticMeth = new OutMessage(Agent.SShowMessage);

//定义一个多点委托
OutMessage MultiDele = new OutMessage(ag.ShowMessage);
MultiDele += new OutMessage(Agent.SShowMessage);

singleDele(" delegate instance singleDele");
deleStaticMeth(" delegate instance deleStaticMeth");
MultiDele(" this is a MultiDele");
Console.Read();

#endregion应用程序的主入口点。

#endregion公用的方法

#region私用的字段
///<summary>
///定义一个委托类型
///</summary>
private delegate void OutMessage(string msg);
#endregion私有的字段



下面是代理方:
using System;

namespace Visen.Demo.Delegate

///<summary>
/// Agent 类为委托者的代理方,处理委托者委托的事务。
///</summary>
public class Agent

#region公用的方法

#region空的构造函数
///<summary>
///空的构造函数
///</summary>
public Agent()


#endregion空的构造函数

#region显示一条信息到控制台,一个类成员函数作为代理方
///<summary>
///显示一条信息到控制台,一个类成员函数作为代理方
///</summary>
///<param name="msg">显示内容</param>
public void ShowMessage(string msg)

Console.WriteLine("Method ShowMessage out:" + msg + "\n");

#endregion显示一条信息到控制台,一个类成员函数作为代理方

#region显示一条信息到控制台,一个类静态函数作为代理方
///<summary>
///显示一条信息到控制台,一个类静态函数作为代理方
///</summary>
///<param name="msg">显示信息</param>
public static void SShowMessage(string msg)

Console.WriteLine("static Method SShowMessage out:" + msg + "\n");

#endregion显示一条信息到控制台,一个类静态函数作为代理方

#endregion公用的方法


输出为:
This is a delegate demo

Method ShowMessage out: delegate instance singleDele

static Method SShowMessage out: delegate instance deleStaticMeth

Method ShowMessage out: this is a MultiDele

static Method SShowMessage out: this is a MultiDele

可见:方法函数可以是类成员函数,也可以是一个静态成员,只要和委托的签名相同就可以了。

有错的地方,请大家批评指正,谢谢!
参考技术A 1.历史上Windows API经常使用C语言风格的函数指针来创建称为回调函数或简称为回调的实体。【回调(callback)一词本身指的是可以作为参数传给其他代码的一段可执行代码。普通调用往往是高层代码(如应用程序)去调用处在低层的函数(如系统函数、库函数)。而回调时,则是在低层函数执行时调用高层代码。】使用回调,程序员可以使一个函数返回报告给程序中的另一个函数。C风格回调函数问题在于,它们除了提供原始内存地址外无法表示其他信息。而我们希望回调中应该包含更多的类型安全信息,如参数数量和类型、所指向方法的返回值。为达到这一要求,在.NET FRAMEWORK 里,使用了更为安全和面向对象的委托来实现回调。
2. 委托是一个类型安全的对象,它指向程序中另一个(或多个)以后会被调用的方法。委托包含3个重要信息:
所调用方法名称
该方法参数(可选)
该方法返回值(可选)
3.例如我们定义一个名为IntCalc的委托:
public delegate int IntCalc(int x,int y)
它可以指向任何输入两个整数返回一个整数的方法。当用C#处理委托类型时,它会自动产生一个派生自System.MulticastDelegate的密封类,这个类与它的基类System.Delegate一起为委托提供必要的基础设施,以维护以后要调用方法的列表。
C#委托定义生成的密封类有三个编译器生成的方法,这三个方法的参数和返回值基于委托的声明,伪代码如下:
Public sealed Class DelegateName: System.MulticastDelegate

public DelegateName (object target,uint functionAddress);
public delegateReturnValue Invoke(allDelegateInputRefAndOutParams);
public IAsynResult BeginInvoke(allDelegateInputRefAndOutParams,AsynCallback cb,object state);
public delegateReturnValue EndInvoke(allDelegateInputRefAndOutParams,IAsyncResult result);

4.由于上述几个函数涉及多线程调用,本人对此不甚了解,不再赘述。
相对于这些原理性的东西,相信大家更加关心的是委托的用法,
5.对于委托的用法,我还要补充两点。一是匿名方法,一是Lamda表达式。
由于一些方法很少被调用委托之外的任何程序调用,从生产效率的角度来说,手工定义一个由委托对象调用的方法有点繁琐。为解决这一情况,可以在事件注册时直接将一个委托与一段代码相关联,这种代码的正式名称是匿名方法。
6.如下例:
已经定义了public delegate int IntCalc(int x,int y)
我们可以这样进行注册
IntCalc cal =new IntCalc( delegate(int x , int y) return x + y;);
匿名方法可以使我们访问定义它们的方法的局部变量,这些局部变量称为匿名方法的外部变量。

int t;
IntCalc cal = delegate(int x , int y) return x * y*t;
Lamda表达式提供了更为简单的匿名方法注册方式,彻底简化了对.NET委托类型的使用。
Lamda表达式是这样编写的,首先定义一个参数列表,“=>”标记紧随其后,然后就是表达式。表达式可以理解为:ArgumentToProcess => StatesToProcessThem.
上述委托注册可以写为
IntCalc cal =new IntCalc( ( x, y)=>(x+y));
7.委托可以在泛型中得到广泛应用,利用委托,我们可以自定义大小比较、匹配等的规则,从而可以很方便的调用List自带函数,免去许多不必要的麻烦,大大提高编程效率。
参考技术B 其实你双击产生的代码就是和委托来绑定带一起的啊

在 Laravel 中委托权限

【中文标题】在 Laravel 中委托权限【英文标题】:Entrust permission in Laravel 【发布时间】:2015-07-04 10:28:24 【问题描述】:

我正在使用 laravel 5.0。我正在使用 Entrust 获取用户权限。 当我尝试执行以下功能时

Entrust::can('customers-views')

我收到这样的错误。这是什么原因。我该如何解决这个问题?

Class 'App\Http\Controllers\Entrust' not found

我可以在控制器中使用 Entrust:can 功能吗?

【问题讨论】:

【参考方案1】:

你可以试试吗

\Entrust::can('customers-views')

或在文件顶部添加use path\to\Entrust 行。

【讨论】:

以上是关于C#中委托如何使用?的主要内容,如果未能解决你的问题,请参考以下文章

C#中委托和事件的区别

C#中委托实现的异步编程

c#中委托的作用是啥?

关于C#中委托的多播应用问题

C#中的委托如何应用

细说委托