C#(或其他语言)代表的使用

问题描述:

我一直在想,代表如何可以有用,我们为什么要使用它们?其他则是Visual Studio文档中的类型安全和所有这些优点,代表的真实世界用途是什么。C#(或其他语言)代表的使用

我已经找到了一个,它非常有针对性。

using System; 

namespace HelloNamespace { 

    class Greetings{ 
    public static void DisplayEnglish() { 
      Console.WriteLine("Hello, world!"); 
    } 
    public static void DisplayItalian() { 
      Console.WriteLine("Ciao, mondo!"); 
    } 
    public static void DisplaySpanish() { 
      Console.WriteLine("Hola, imundo!"); 
     } 
    } 

    delegate void delGreeting(); 

    class HelloWorld { 
     static void Main(string [] args) { 

    int iChoice=int.Parse(args[0]); 
    delGreeting [] arrayofGreetings={ 
      new delGreeting(Greetings.DisplayEnglish), 
      new delGreeting(Greetings.DisplayItalian), 
      new delGreeting(Greetings.DisplaySpanish)}; 

    arrayofGreetings[iChoice-1](); 
     } 
    } 
} 

但是,这并不表明我到底使用委托,而不是有条件的优势,“如果... {}”,它解析参数和运行方法。

有谁知道为什么它是更好地在这里使用委托,而不是“如果... {}”。你还有其他的例子可以证明代表的有用性。

谢谢!

+0

啊,那是的多尼斯·马歇尔的Visual C#2008年的第一个例子...不是真正合适的第一个Hello World示例,但仍然... – 2009-07-06 08:24:06

+0

不,我发现它在同一作者的“编程Microsoft Visual C#2005:语言”,好,他为C#2008做了一个新版本,我将有一个看看吧 – 2009-07-06 08:34:52

最常见的真实世界的日常使用代表说我可以想到在C#中将事件处理。当你在WinForm上有一个按钮,并且当按钮被点击时你想要做某些事情,那么你所做的是你最终注册一个委托函数,当它被点击时被按钮调用。

所有这一切都发生自动为您在由Visual Studio本身生成的代码在幕后,所以你可能看不到它发生在哪里。

一个真实世界的情况下可能会更对你有用是,如果你想使人们可以用将读取的数据从互联网饲料库,并通知他们当饲料已被更新。通过使用委托,那么使用库的程序员将能够在更新订阅源时调用自己的代码。

委托是的注入功能入的方法的最佳方式。因此,他们极大地帮助代码重用

想想看,假设你有一组具有几乎相同的功能,但在短短的几行代码的变化相关方法。您可以将这些方法共有的所有内容重构为单一方法,然后您可以通过委托注入专用功能。

以LINQ使用的所有IEnumerable扩展方法为例。所有这些定义常见功能,但需要一个委托传递给他们定义返回数据是如何预测,或如何将数据筛选,排序等..

Lambda表达式
代表主要与事件一起使用。但动态语言显示了它们更广泛的用途。这就是为什么我们得到Lambda expressions之前,代表们一直没有得到充分利用,直到C#3.0。使用Lambda表达式(生成委托方法)很容易做到这一点

现在想象一下你有一个IEnumerable字符串。您可以轻松定义委托(使用Lambda表达式或任何其他方式)并将其应用于每个元素上(例如修剪多余空间)。并且不使用循环语句。当然你的代表可能会做更复杂的任务。

代表用于在其他类中“调用”代码(可能不一定在相同,类或者.cs中,甚至是相同的程序集中)。

在你的例子中,委托可以简单地被if语句取代,如你所指出的那样。

但是,委托是指向代码中某处“活”的函数的指针,因为组织原因,例如您无法访问(轻松)。

另一个我觉得很有用的用法是如果我希望执行相同的操作,传递相同的数据或在同一对象类型的多个实例中触发相同的操作。

我将尝试列出一些例子,是超越了简单的if-else场景:

  1. 实现回调。例如,您正在解析XML文档,并且希望在遇到特定节点时调用特定函数。您可以将代表传递给函数。

  2. 实施策略设计模式。将委托分配给所需的算法/策略实施。

  3. 匿名委托在你希望某个功能在单独的线程上执行的情况下(并且这个功能没有任何东西可以发送回主程序)。

  4. 其他人建议的事件订阅。

在您的例子您greating是相同的,所以你真正需要的是一个字符串数组。

如果您希望获得使用Command模式代表的,假设有:

public static void ShakeHands() 
{ ... } 

public static void HowAreYou() 
{ ... } 

public static void FrenchKissing() 
{ ... } 

可以替代的方法具有相同签名,但不同的动作。 你选择的方式太简单了,我的建议是 - 去找一本C#的深度书。

在.NET中,从后台线程更新UI时也需要委托。由于您不能从与创建控件的线程不同的线程更新控件,因此您需要使用创建线程的上下文(主要使用this.Invoke)来调用更新代码。

代表和相关语法糖有显著改变了C#世界(2.0+) 委托是类型安全的函数指针 - 所以您使用委托任何你想要调用/在时间未来点执行代码块。

广泛的部分,我能想到的

回调/事件处理程序:这样做时EventX发生。或者当您准备好使用异步方法调用的结果时执行此操作。

myButton.Click += delegate { Console.WriteLine("Robbery in progress. Call the cops!"); } 

LINQ:选择您想要向下传递管道之前做的每个元素的东西元素的投影等。例如选择均匀的所有数字,然后返回每个数字的平方

var list = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } 
       .Where(delegate(int x) { return ((x % 2) == 0); }) 
       .Select(delegate(int x) { return x * x; });  
// results in 4, 16, 36, 64, 100 

下面是一个真实世界的例子。我在包装某种外部电话时经常使用委托。例如,我们有一个旧的应用程序服务器(我希望它会消失),我们通过.Net远程连接来连接。我会打电话给在一个委托的应用服务器从这样一个“safecall”功能:

private delegate T AppServerDelegate<T>(); 

private T processAppServerRequest<T>(AppServerDelegate<T> delegate_) { 
      try{ 
       return delegate_(); 
      } 
      catch{ 
       //Do a bunch of standard error handling here which will be 
       //the same for all appserver calls. 
      } 

     } 

//Wrapped public call to AppServer 
public int PostXYZRequest(string requestData1, string requestData2, 
    int pid, DateTime latestRequestTime){ 
      processAppServerRequest<int>(
       delegate { 
       return _appSvr.PostXYZRequest(
        requestData1, 
        requestData2, 
        pid, 
        latestRequestTime); 
       }); 

显然错误处理做了一些比这更好的,但你得到的粗略的想法。

代表只是.Net的first class functions的实现,并允许使用它们的语言提供Higher Order Functions

这种风格的主要好处是可以将公共方面抽象为一个函数,它只需要执行它(例如遍历数据结构)并提供另一个函数(或多个函数)即可要求随着事情顺利进行。

规范化的功能实例是mapfold,可以通过提供其他操作来改变它以做各种事情。

如果你想总结一个T的列表并且有一些函数add需要两个T并且把它们加在一起然后(通过部分应用)fold add 0变成总和。 fold multiply 1将成为产品,fold max 0最大。在所有这些例子中,程序员都不需要考虑如何遍历输入数据,不用担心输入为空时该怎么做。

这些都是简单的例子(尽管它们与其他结合起来可能会令人惊讶的强大),但考虑树遍历(更复杂的任务),所有这些都可以抽象出treefold函数。树形折叠函数的编写可能很难,但是一旦完成,它可以被广泛地重新使用,而不必担心错误。

这与概念和设计上类似于将foreach循环结构添加到传统命令式语言中,其思想是您不必自己编写循环控制(因为它引入了由一个错误导致的机会,增加冗长,在你正在做的每一个条目而不是显示如何你得到的每个条目什么方式获得。高阶函数只是让你的结构的遍历从该怎么办分离,同时穿越可延伸内语言本身。

应当指出的是,在C#中代表们通过lambda表达式在很大程度上取代,因为编译器可以简单地对待它作为一个更简洁代表如果想要,但也可以*穿过表达拉姆达表示到它被传递给,以允许愿望的(通常是复杂的)重组或重新定位到一些其它结构域的功能比如通过Linq-to-Sql进行数据库查询。

c-style函数指针的.net委托模型的一个主要优点是它们实际上是一个元组(两部分数据)要调用的函数以及函数将被调用的可选对象。这使您可以通过与有关国家这是更强大的功能。由于编译器可以用它来构建你的背部(1)班的背后,实例化这个类的一个新实例,并把本地变量进入从而使closures

(1)不始终做到这一点,但现在这是一个实现细节