デリゲートがインスタンス化されると、関数が常に使用されるため、関数を個別に定義しますが、多くの場合、これを実行したくないが、関数を直接定義して直接使用します。現時点では、無名関数またはラムダ式を使用できます。それぞれC#2.0とC#3.0で導入されています。
ラムダ式
ラムダ式(またはλ式と呼ばれる)は、実際には、関数のヘッダーと関数本体の前に、記号=>
を使用して表すために、関数名を書き込むのではなく、書き込みヘッドと関数の本体の直接関数です。そして、この関数をデリゲートに直接割り当てるか、別の関数のパラメーターとして割り当てます。例えば:
MyDelegate d = (double x) => {
return x + 5; };
MyDelegate d = new MyDelegate((double x) => {
return x + 5; });
Lambda式は常にデリゲート型と互換性があるため、その型はコンパイラーによって自動的に推測されるため、パラメーターの型は省略でき、パラメーター変数の名前のみを書き込むことができます。例えば:
MyDelegate d = (x) => {
return x + 5; };
パラメーターが1つしかない場合は、パラメーターの括弧も省略できます。戻り式またはステートメントが1つしかない場合は、関数の中括弧も省略できます。例えば:
MyDelegate d = x => {
return x + 5; };
Mydelegate d = x => x + 5;
関数の数値積分では、Delegate
ラムダ式を使用して次のように記述できます。
result = Intergral(x => 2 * x + 1, 0, 1, 0.01);
result = Intergral(x => Math.Sin(x), 0, Math.PI, 0.01);
Lambda式は埋め込み関数、より正確には埋め込みデリゲート変数であると言えます。
匿名関数
匿名関数は名前のない関数です。関数が定義された直後にデリゲートに割り当てられる場合、名前は必要ありません。そうでない場合、コンパイラは自動的に名前を生成します。これが無名関数であることを示すには、その前にキーワードを追加する必要がありますdelegate
。例えば:
MyDelegate d = delegate (double x){
return x + 5; };
ここで注意する必要があります。delegate
ここでは無名関数を意味しますが、delegate
この単語はデリゲートタイプの定義にも使用できますが、コンパイラーが混乱することはありません。
Visible、Lambda式と無名関数は似ていますが、無名関数を使用=>
して表現するように委任し、Lambda式を使用して表現する点が異なります。Lambdaはさらに省略できるため、匿名関数は現在ほとんど使用されていません。
匿名関数の目的がある場合、匿名関数は次のようなパラメータータイプとパラメーター名を記述する必要がないということです。
MyDelegate d = delegate {
return 100; };
ただし、Lambda式を使用するのは面倒ではありません。
MyDelegate d = x => 100;
プロパティとインデクサーの省略形
ラムダ式(および無名関数)は、関数を呼び出すときのパラメーターの記述を簡素化できるだけでなく、C#6.0以降では、メソッド、属性、インデクサー、および「式本体メンバー」(式)と呼ばれるその他のメンバーの定義も簡素化できます。ボディメンバー)。例えば:
public double Square(double n) => n * n; // 方法
public double Dist => Math.Sqrt(X * X + Y * Y); // 只读属性
public int this[int a] => members[a]; // 只读索引器
最初の文と2番目の文は、それぞれ属性とメソッドを定義します(のみget
、いいえset
)。
C#7.0以降では、次のように、構築メソッドでより多くの「式本体メンバー」を使用したり、属性を設定したりすることもできます。
public Person(string name) => names.TryAdd(id, name);
public string Name{
get => names[id]; // getters
set => names[id] = value; // setters
}
3つのサンプルプログラム:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
class Program
{
static void Main(string[] args) {
Console.WriteLine("Hello World!");
Example2();
Console.WriteLine("---------------------分割线---------------------");
Example3();
}
// 示例1, 使用线程
private void Example1() {
// csharp 1.0
// 使用委托,使用已定义好的函数
new Thread(new ThreadStart(MyFun)).Start();
// csharp 2.0
// 省略委托:MyFun自动实例化为ThreadStart委托
new Thread(MyFun).Start();
// 匿名方法
new Thread(new ThreadStart(delegate () {
Console.WriteLine("my function"); })).Start();
// 匿名方法, 省略参数列表
new Thread(new ThreadStart(delegate {
Console.WriteLine("my function"); })).Start();
// 匿名方法, 自动转委托
new Thread(delegate () {
Console.WriteLine("my function"); }).Start();
// csharp 3.0
// Lambda表达式
new Thread(() => {
Console.WriteLine("my function"); }).Start();
}
private void MyFun() {
Console.WriteLine("my function");
}
// 示例2, 使用事件
public class TestEventArgs
{
// 事件数据
public string name;
public TestEventArgs(string name) {
this.name = name; }
}
public delegate void TestHandler(object sender, TestEventArgs e); // 1.声明委托, 公用的
public class TestEvent
{
public event TestHandler Test; // 2.声明事件, 在一个类中
public void UseTestEvent() {
Test(this, new TestEventArgs("name")); } // 调用事件Test
}
private static void Example2() {
TestEvent testEvent = new TestEvent();
// csharp 1.0
// 使用委托, 使用自定义函数
testEvent.Test += new TestHandler(TestEvent_Test); // 3.在别的类中注册事件
// csharp 2.0
// 自动转委托
testEvent.Test += TestEvent_Test;
// 匿名方法
testEvent.Test += new TestHandler(delegate (object sender, TestEventArgs e) {
Console.WriteLine("TestEvent_Test " + e.name); });
// 匿名方法, 自动转委托
testEvent.Test += delegate (object sender, TestEventArgs e) {
Console.WriteLine("TestEvent_Test " + e.name); };
// csharp 3.0
// 使用Lambda表达式
testEvent.Test += (object sender, TestEventArgs e) => {
Console.WriteLine("TestEvent_Test " + e.name); };
testEvent.Test += (sender, e) => {
Console.WriteLine("TestEvent_Test " + e.name); };
testEvent.UseTestEvent();
}
private static void TestEvent_Test(object sender, TestEventArgs e) {
Console.WriteLine("TestEvent_Test " + e.name);
}
// 示例3, 数组排序
class Book
{
public string title;
public double price;
public Book(string title, double price) {
this.title = title; this.price = price; }
}
private static void Example3() {
Random rnd = new Random();
Book[] books = new Book[10];
for (int i = 0; i < books.Length; i++) books[i] = new Book("Book" + i, rnd.Next(100));
foreach (Book book in books) Console.WriteLine(book.title + " " + book.price);
Console.WriteLine();
// csharp 1.0
Array.Sort(books, new MyComparer());
// csharp 2.0
// 使用Comparison委托
Array.Sort<Book>(books, new Comparison<Book>(delegate (Book book1, Book book2) {
return (int)(book1.price - book2.price); }));
Array.Sort<Book>(books, delegate (Book book1, Book book2) {
return (int)(book1.price - book2.price); });
// csharp 3.0
Array.Sort<Book>(books, (Book book1, Book book2) => (int)(book1.price - book2.price));
Array.Sort<Book>(books, (book1, book2) => (int)(book1.price - book2.price)); //省略参数类型
foreach (Book book in books) Console.WriteLine(book.title + " " + book.price);
// 使用Linq
IOrderedEnumerable<Book> result = from book in books orderby book.price select book;
var result1 = from book in books where book.price >= 0 orderby book.price select book.title;
foreach (string s in result1) Console.WriteLine(s);
var result2 = books
.Where<Book>(b => b.price >= 0)
.OrderBy<Book, double>(b => b.price, Comparer<double>.Default)
.Select<Book, Book>(book => book);
foreach (Book b in result2) Console.WriteLine(b.price + " ");
}
class MyComparer : System.Collections.IComparer
{
public int Compare(object x, object y) {
return (int)(((Book)x).price - ((Book)y).price);
}
}
}