本文翻译自:When & why to use delegates? [duplicate]

This question already has answers here : 这个问题已经在这里有了答案 :
Where do I use delegates? 我在哪里使用代表? [closed] (8 answers) [已关闭] (8个答案)
Closed 6 years ago . 6年前关闭。

I'm relatively new in C#, & I'm wondering when to use Delegates appropriately . 我在C#中相对较新,我想知道何时适当使用Delegates 。 they are widely used in events declaration, but when should I use them in my own code and why are they useful? 它们在事件声明中被广泛使用,但是我什么时候应该在自己的代码中使用它们, 为什么它们有用? why not to use something else? 为什么不使用其他东西?

I'm also wondering when I have to use delegates and I have no other alternative . 我也想知道何时必须使用委托,而没有其他选择 。

Thank you for the help! 感谢您的帮助!

EDIT: I think I've found a necessary use of Delegates here 编辑:我想我已经在这里找到了必要的代表使用


#1楼

参考:https://stackoom.com/question/8TL0/何时及为何使用代表-重复


#2楼

I've just go my head around these, and so I'll share an example as you already have descriptions but at the moment one advantage I see is to get around the Circular Reference style warnings where you can't have 2 projects referencing each other. 我已经解决了这些问题,因此我将分享一个示例,因为您已经有了描述,但是目前我看到的一个优势是绕过了“循环引用”样式警告,在该警告中您不能有两个引用每个项目的项目。其他。

Let's assume an application downloads an XML, and then saves the XML to a database. 假设应用程序下载XML,然后将XML保存到数据库。

I have 2 projects here which build my solution: FTP and a SaveDatabase. 我在这里有2个项目可以构建我的解决方案:FTP和SaveDatabase。

So, our application starts by looking for any downloads and downloading the file(s) then it calls the SaveDatabase project. 因此,我们的应用程序首先查找所有下载内容并下载文件,然后调用SaveDatabase项目。

Now, our application needs to notify the FTP site when a file is saved to the database by uploading a file with Meta data (ignore why, it's a request from the owner of the FTP site). 现在,我们的应用程序需要通过上传带有元数据的文件来将文件保存到数据库时通知FTP站点(忽略原因,这是FTP站点所有者的请求)。 The issue is at what point and how? 问题在于什么时候以及如何解决? We need a new method called NotifyFtpComplete() but in which of our projects should it be saved too - FTP or SaveDatabase? 我们需要一个称为NotifyFtpComplete()的新方法,但也应将其保存在我们的哪个项目中-FTP还是SaveDatabase? Logically, the code should live in our FTP project. 从逻辑上讲,该代码应存在于我们的FTP项目中。 But, this would mean our NotifyFtpComplete will have to be triggered or, it will have to wait until the save is complete, and then query the database to ensure it is in there. 但是,这意味着我们将必须触发NotifyFtpComplete,或者必须等到保存完成后,再查询数据库以确保该数据库位于其中。 What we need to do is tell our SaveDatabase project to call the NotifyFtpComplete() method direct but we can't; 我们需要做的就是告诉我们的SaveDatabase项目直接调用NotifyFtpComplete()方法,但是我们不能这样做。 we'd get a ciruclar reference and the NotifyFtpComplete() is a private method. 我们将获得ciruclar参考,并且NotifyFtpComplete()是私有方法。 What a shame, this would have worked. 真可惜,这本来可以。 Well, it can. 好吧,可以。

During our application's code, we would have passed parameters between methods, but what if one of those parameters was the NotifyFtpComplete method. 在应用程序的代码期间,我们将在方法之间传递参数,但是如果其中一个参数是NotifyFtpComplete方法,该怎么办。 Yup, we pass the method, with all of the code inside as well. 是的,我们传递了方法,其中也包含了所有代码。 This would mean we could execute the method at any point, from any project. 这意味着我们可以在任何项目的任何位置执行该方法。 Well, this is what the delegate is. 好,这就是委托人。 This means, we can pass the NotifyFtpComplete() method as a parameter to our SaveDatabase() class. 这意味着,我们可以将NotifyFtpComplete()方法作为参数传递给SaveDatabase()类。 At the point it saves, it simply executes the delegate. 保存时,它只是执行委托。

See if this crude example helps (pseudo code). 看看这个简单的例子是否有帮助(伪代码)。 We will also assume that the application starts with the Begin() method of the FTP class. 我们还将假定应用程序以FTP类的Begin()方法开头。

class FTP
{public void Begin(){string filePath = DownloadFileFromFtpAndReturnPathName();SaveDatabase sd = new SaveDatabase();sd.Begin(filePath, NotifyFtpComplete());}private void NotifyFtpComplete(){//Code to send file to FTP site}
}class SaveDatabase
{private void Begin(string filePath, delegateType NotifyJobComplete()){SaveToTheDatabase(filePath);/* InvokeTheDelegate - * here we can execute the NotifyJobComplete* method at our preferred moment in the application,* despite the method being private and belonging* to a different class.*/NotifyJobComplete.Invoke();}
}

So, with that explained, we can do it for real now with this Console Application using C# 因此,在解释了这一点之后,我们现在可以使用C#通过此控制台应用程序真正做到这一点

using System;namespace ConsoleApplication1
{/* I've made this class private to demonstrate that * the SaveToDatabase cannot have any knowledge of this Program class.*/class Program{static void Main(string[] args){//Note, this NotifyDelegate type is defined in the SaveToDatabase projectNotifyDelegate nofityDelegate = new NotifyDelegate(NotifyIfComplete);SaveToDatabase sd = new SaveToDatabase();            sd.Start(nofityDelegate);Console.ReadKey();}/* this is the method which will be delegated -* the only thing it has in common with the NofityDelegate* is that it takes 0 parameters and that it returns void.* However, it is these 2 which are essential.* It is really important to notice that it writes* a variable which, due to no constructor,* has not yet been called (so _notice is not initialized yet).*/ private static void NotifyIfComplete(){Console.WriteLine(_notice);}private static string _notice = "Notified";}public class SaveToDatabase{public void Start(NotifyDelegate nd){/* I shouldn't write to the console from here, * just for demonstration purposes*/Console.WriteLine("SaveToDatabase Complete");Console.WriteLine(" ");nd.Invoke();}}public delegate void NotifyDelegate();
}

I suggest you step through the code and see when _notice is called and when the method (delegate) is called as this, I hope, will make things very clear. 我建议您单步执行代码,看看何时调用_notice以及何时调用方法(委托),这样可以使事情变得很清楚。

However, lastly, we can make it more useful by changing the delegate type to include a parameter. 但是,最后,我们可以通过更改委托类型以包含参数来使其更加有用。

using System.Text;namespace ConsoleApplication1
{/* I've made this class private to demonstrate that the SaveToDatabase* cannot have any knowledge of this Program class.*/class Program{static void Main(string[] args){SaveToDatabase sd = new SaveToDatabase();/* Please note, that although NotifyIfComplete()* takes a string parameter, we do not declare it,* all we want to do is tell C# where the method is* so it can be referenced later,* we will pass the parameter later.*/var notifyDelegateWithMessage = new NotifyDelegateWithMessage(NotifyIfComplete);sd.Start(notifyDelegateWithMessage );Console.ReadKey();}private static void NotifyIfComplete(string message){Console.WriteLine(message);}}public class SaveToDatabase{public void Start(NotifyDelegateWithMessage nd){/* To simulate a saving fail or success, I'm just going* to check the current time (well, the seconds) and* store the value as variable.*/string message = string.Empty;if (DateTime.Now.Second > 30)message = "Saved";elsemessage = "Failed";//It is at this point we pass the parameter to our method.nd.Invoke(message);}}public delegate void NotifyDelegateWithMessage(string message);
}

#3楼

I consider delegates to be Anonymous Interfaces . 我认为代表是匿名接口 。 In many cases you can use them whenever you need an interface with a single method, but you don't want the overhead of defining that interface. 在许多情况下,只要需要使用单一方法的接口,就可以使用它们,但又不需要定义该接口的开销。


#4楼

Delegates are extremely useful when wanting to declare a block of code that you want to pass around. 当要声明要传递的代码块时,委托非常有用。 For example when using a generic retry mechanism. 例如,当使用通用重试机制时。

Pseudo: 伪:

function Retry(Delegate func, int numberOfTimes)try{func.Invoke();}catch { if(numberOfTimes blabla) func.Invoke(); etc. etc. }

Or when you want to do late evaluation of code blocks, like a function where you have some Transform action, and want to have a BeforeTransform and an AfterTransform action that you can evaluate within your Transform function, without having to know whether the BeginTransform is filled, or what it has to transform. 或者,当您想对代码块进行后期评估时,例如具有一些Transform操作的函数,并且希望可以在自己的Transform函数中进行评估的BeforeTransformAfterTransform操作,而不必知道是否已填充BeginTransform ,或它必须进行的转换。

And of course when creating event handlers. 当然是在创建事件处理程序时。 You don't want to evaluate the code now, but only when needed, so you register a delegate that can be invoked when the event occurs. 您现在不想评估代码,而只是在需要时评估代码,因此您注册了一个在事件发生时可以调用的委托。


#5楼

I agree with everything that is said already, just trying to put some other words on it. 我同意已经说过的一切,只是尝试在上面加上一些其他字眼。

A delegate can be seen as a placeholder for a/some method(s). 可以将委托视为一种/某些方法的占位符。

By defining a delegate, you are saying to the user of your class, " Please feel free to assign, any method that matches this signature, to the delegate and it will be called each time my delegate is called ". 通过定义委托,您对班级的用户说:“ 请随意将与该签名匹配的任何方法分配给委托,每次我的委托被调用时,都会调用该委托 。”

Typical use is of course events. 当然,典型的用法是事件。 All the OnEventX delegate to the methods the user defines. 所有OnEventX都委托给用户定义的方法。

Delegates are useful to offer to the user of your objects some ability to customize their behavior. 委托对于为对象的用户提供一些自定义其行为的功能很有用。 Most of the time, you can use other ways to achieve the same purpose and I do not believe you can ever be forced to create delegates. 在大多数情况下,您可以使用其他方式来实现相同的目的,而且我认为您永远不会被迫创建委托。 It is just the easiest way in some situations to get the thing done. 在某些情况下,这只是完成任务的最简单方法。


#6楼

Delegates Overview 代表概述

Delegates have the following properties: 代表具有以下属性:

  • Delegates are similar to C++ function pointers, but are type safe. 委托类似于C ++函数指针,但类型安全。
  • Delegates allow methods to be passed as parameters. 委托允许将方法作为参数传递。
  • Delegates can be used to define callback methods. 委托可用于定义回调方法。
  • Delegates can be chained together; 代表可以串在一起; for example, multiple methods can be called on a single event. 例如,可以在单个事件上调用多个方法。
  • Methods don't need to match the delegate signature exactly. 方法不需要完全匹配委托签名。 For more information, see Covariance and Contra variance. 有关更多信息,请参见协方差和对比度方差。
  • C# version 2.0 introduces the concept of Anonymous Methods, which permit code blocks to be passed as parameters in place of a separately defined method. C#2.0版引入了匿名方法的概念,该方法允许将代码块作为参数来传递,以代替单独定义的方法。

何时及为何使用代表? [重复]相关推荐

  1. 温故知新MySQL--如何在MySQL表中删除重复行

    2019独角兽企业重金招聘Python工程师标准>>> 如何在MySQL表中删除重复行 在实际应用中,会有需要删除重复数据的场景.这里简单介绍下如何删除重复的数据 1. 准备数据 C ...

  2. sudo: apt-get:找不到命令_Linux重复执行历史命令方法详解

    Linux 下,如果要执行一条或多条之前输过的指令,要怎么处理?很多人会想到使用上下箭头去翻查历史输入的命令.这当然是可以了,除了这种方法,本文再介绍另外 5 种方法来实现这样的效果. 在正式开始之前 ...

  3. 正则表达式---重复

    重复 * 零次或多次匹配前面的字符或子表达式 + 一次或多次匹配前面的字符或子表达式 ? 零次或一次匹配前面的字符或子表达式 重复特定次数 {n,m} 重复特定的次数 n代表重复的最少次数 m代表重复 ...

  4. linux怎么重复命令,Linux系统中重复执行历史命令的方法有哪些?

    今天小编要跟大家分享的文章是关于Linux系统中重复执行历史命令的方法有哪些?各位正在从事Linux运维工作的小伙伴们,如果要执行一条或多条之前输过的指令,要怎么处理?很多人会想到使用上下箭头去翻查历 ...

  5. R语言 数据清洗 重复值所在的行 重复 的筛选与去除,唯一ID出现重复 no重复处理

    住院号 姓名 等唯一值变量的检查与筛选 重复值所在的行 使用本地数据 鸢尾花(yuān wěi huā)做示例 [R语言][数据清洗]重复ID数据获取比对 #加载内置数据 data(iris) dat ...

  6. python 正则表达式贪婪模式与非贪婪模式

    1 贪婪模式与非贪婪模式 的理解 1.1 贪婪模式: 是尽可能的多地匹配字符 ,贪婪模式一般是在元符号后面没有添加? 1.2 非贪婪模式(懒惰模式): 是尽可能的少匹配字符,非贪婪模式一般是元符号后面 ...

  7. linux下的vi与vim

    vi与vim vi编辑器是所有Unix及Linux系统下标准的编辑器,他就相当于windows系统中的记事本一样,它的强大不逊色于任何最新的文本编辑器.他是我们使用Linux系统不能缺少的工具.由于对 ...

  8. IDEA + Vim = 得劲

    本教程并不是单纯的 vim 操作介绍,更多的是与 Intellj Idea 进行配合.需要同时具备 Intellj Idea 和 vim 使用基础的同学学习. 01. 简介 Vim 是一个高度可配置的 ...

  9. 计算机视觉四大基本任务(分类、定位、检测、分割)

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 转载于:作者 | 张皓 来源 | 知乎(https://zhuan ...

最新文章

  1. 牛客 - 字典序(思维)
  2. ArchLinux学习之环境变量
  3. Redis的超时命令和垃圾回收策略
  4. 印度 语言简称_保存印度的语言和文化:图卢维基百科的诞生
  5. ecnu1244 积木游戏
  6. 华为发布最强 AI 处理器昇腾 910,全场景 AI 框架 MindSpore 将开源
  7. 洛谷 P2622 关灯问题II (状态压缩+BFS)
  8. 小游戏---html飞翔的小鸟
  9. WinRunner在项目中的作用
  10. RapidMiner介绍与实践(二)贝叶斯分类器
  11. Android SVN版本控制器
  12. 原来人脸识别技术是“酱紫”实现的!
  13. Approximation of functions in fractional Sobolev spaces
  14. 算法基础课【合集1】
  15. response响应讲解
  16. XILINX FPGA OV5640 摄像头驱动(一)
  17. mysql日期函数_英文简写月的转换
  18. Java入门第三季-综合实战:简易扑克牌游戏
  19. 部署以太坊智能合约01
  20. NKD编译opus-1.2.1

热门文章

  1. Unity3d之Http通讯GET方法和POST方法
  2. Cocos2d-x之LUA脚本引擎深入分析
  3. touchend与click顺序
  4. HTML5语义元素的使用
  5. ROBOTS.TXT在SEO优化中的运用(ROBOTS.TXT SEO优化实战)
  6. Coolite Toolkit学习笔记四:容器控件之FiledSet、Panel和Window
  7. 中国IT业发展案例剖析之--豪杰解霸
  8. Linux对变量的截取替换
  9. nil 作比较时应该加上双引号
  10. 源码实现 -- strdel