Delegates and lambdas

Delegates define a type, which specify a particular method signature. A method (static or instance) that satisfies this signature can be assigned to a variable of that type, then called directly (with the appropriate arguments) or passed as an argument itself to another method and then called. The following example demonstrates delegate use.

C#

public class Program
{

  public delegate string Reverse(string s);

  static string ReverseString(string s)
  {
      return new string(s.Reverse().ToArray());
  }

  static void Main(string[] args)
  {
      Reverse rev = ReverseString;

      Console.WriteLine(rev("a string"));
  }
}
  • On line 4 we create a delegate type of a certain signature, in this case a method that takes a string parameter and then returns a string parameter.
  • On line 6, we define the implementation of the delegate by providing a method that has the exact same signature.
  • On line 13, the method is assigned to a type that conforms to the Reverse delegate.
  • Finally, on line 15 we invoke the delegate passing a string to be reversed.

In order to streamline the development process, .NET includes a set of delegate types that programmers can reuse and not have to create new types. These are Func<>Action<> and Predicate<>, and they can be used in various places throughout the .NET APIs without the need to define new delegate types. Of course, there are some differences between the three as you will see in their signatures which mostly have to do with the way they were meant to be used:

  • Action<> is used when there is a need to perform an action using the arguments of the delegate.
  • Func<> is used usually when you have a transformation on hand, that is, you need to transform the arguments of the delegate into a different result. Projections are a prime example of this.
  • Predicate<> is used when you need to determine if the argument satisfies the condition of the delegate. It can also be written as a Func<T, bool>.

We can now take our example above and rewrite it using the Func<> delegate instead of a custom type. The program will continue running exactly the same.

C#

public class Program
{

  static string ReverseString(string s)
  {
      return new string(s.Reverse().ToArray());
  }

  static void Main(string[] args)
  {
      Func<string, string> rev = ReverseString;

      Console.WriteLine(rev("a string"));
  }
}

For this simple example, having a method defined outside of the Main() method seems a bit superfluous. It is because of this that .NET Framework 2.0 introduced the concept of anonymous delegates. With their support you are able to create "inline" delegates without having to specify any additional type or method. You simply inline the definition of the delegate where you need it.

For an example, we are going to switch it up and use our anonymous delegate to filter out a list of only even numbers and then print them to the console.

C#

public class Program
{

  public static void Main(string[] args)
  {
    List<int> list = new List<int>();

    for (int i = 1; i <= 100; i++)
    {
        list.Add(i);
    }

    List<int> result = list.FindAll(
      delegate(int no)
      {
          return (no%2 == 0);
      }
    );

    foreach (var item in result)
    {
        Console.WriteLine(item);
    }
  }
}

Notice the highlighted lines. As you can see, the body of the delegate is just a set of expressions, as any other delegate. But instead of it being a separate definition, we’ve introduced it ad hoc in our call to the FindAll() method of the List<T> type.

However, even with this approach, there is still much code that we can throw away. This is where lambda expressions come into play.

Lambda expressions, or just "lambdas" for short, were introduced first in C# 3.0, as one of the core building blocks of Language Integrated Query (LINQ). They are just a more convenient syntax for using delegates. They declare a signature and a method body, but don’t have an formal identity of their own, unless they are assigned to a delegate. Unlike delegates, they can be directly assigned as the left-hand side of event registration or in various Linq clauses and methods.

Since a lambda expression is just another way of specifying a delegate, we should be able to rewrite the above sample to use a lambda expression instead of an anonymous delegate.

C#

public class Program
{

  public static void Main(string[] args)
  {
    List<int> list = new List<int>();

    for (int i = 1; i <= 100; i++)
    {
        list.Add(i);
    }

    List<int> result = list.FindAll(i => i % 2 == 0);

    foreach (var item in result)
    {
        Console.WriteLine(item);
    }
  }
}

If you take a look at the highlighted lines, you can see how a lambda expression looks like. Again, it is just a very convenient syntax for using delegates, so what happens under the covers is similar to what happens with the anonymous delegate.

Again, lambdas are just delegates, which means that they can be used as an event handler without any problems, as the following code snippet illustrates.

C#

public MainWindow()
{
    InitializeComponent();

    Loaded += (o, e) =>
    {
        this.Title = "Loaded";
    };
}
时间: 2024-10-14 07:10:50

Delegates and lambdas的相关文章

【Xamarin笔记】Events, Protocols and Delegates

Events, Protocols and Delegates   事件.协议和委托 This article presents the key iOS technologies used to receive callbacks and to populate user interface controls with data. These technologies are events, protocols, and delegates. This article explains what

ylbtech-Unitity-CS:Delegates

ylbtech-Unitity-CS:Delegates 1.A,效果图返回顶部 Invoking delegate a: Hello, A! Invoking delegate b: Goodbye, B! Invoking delegate c: Hello, C! Goodbye, C! Invoking delegate d: Goodbye, D! 请按任意键继续. . . 1.B,源代码返回顶部 1.B.1,bookstore.cs // bookstore.cs using Sys

开发该选择Blocks还是Delegates

前文:网络上找了很多关于delegation和block的使用场景,发现没有很满意的解释,后来无意中在stablekernel找到了这篇文章,文中作者不仅仅是给出了解决方案,更值得我们深思的是作者独特的思考和解决问题的方式,因此将这篇文章翻译过来,和诸君探讨,翻译的很多地方不是很到位,望大家提出意见建议. 有人问了我一个很棒的问题,我把这个问题总结为:“开发过程中该选择 blocks or delegates?当我们需要实现回调的时候,使用哪一种方式比较合适呢?” 一般在这种情况下,我喜欢问我自

Java 8: Lambdas和新的集合Stream API

Lambda是Java8的主要特色,Java 8: Lambdas & Java Collections | zeroturnaround.com一文介绍了使用Lambda集合处理大量数据的方法. 首先Java集合引入了内部遍历,原来 LambdaJ下面这种方法也可以在Java8中实现: List<Person> persons = asList(new Person("Joe"), new Person("Jim"), new Person(&

Delegates, Events and Lambda Expression

The content and code of this article is referenced from book Pro C#5.0 and the .NET 4.5 Framework by Apress. The intention of the writing is to review the konwledge and gain better understanding of the .net framework.    Up to this point, most of the

ruby Methods, Procs, Lambdas, and Closures

define simple method定义简单方法 关键字def用于方法定义,在其后是方法名和可选的参数名列表,参数名列表会用一对圆括号括住.构成方法主体的代码放在参数列表之后,end用于结束方法定义. #define a method def factorial(n) if n<1 raise "argument must be >0" elsif n==1 1 else n*factorial(n-1) end end puts factorial(5) 方法返回值

JDK8 Lambdas

#JDK8 Lambdas 基础入门(一) jdk8 重要的一个新特性就是lambdas详细概念我就不一一介绍了,详细的请查看[lambdas](http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/Lambda-QuickStart/index.html#overview) 小栗子认识一下lambda 函数编程:```javapublic class LambdasTest { public static void mai

Java 8 Lambdas

Book Description If you’re a developer with core Java SE skills, this hands-on book takes you through the language changes in Java 8 triggered by the addition of lambda expressions. You’ll learn through code examples, exercises, and fluid explanation

Java 8 不止是Lambdas和Streams

转眼淘系应用升级JDK8已经几个月过去了,Lambdas表达式和Streams APIs的确给同学们带来了编程效率和代码可读性上的提升,代码变得更加简洁直接,更加符合人的思维(看来编程语言的发展也是本着“以人为本”的思路).ATA上讲这两个新特性的文章已经很多了, 大鱼大肉大家吃的差不多,得常常家常小菜吧,下面总结一下常用的Java 8中Lambdas和Streams之外的一些新特性. 1. Default Method Java 单继承的特性决定了一个类只能有1个父类,如果有通用的方法实现就只