- 
- 
- 1.什么是委托
 - 2.委托概述
 - 3.声明委托类型
 - 4.创建委托对象
 - 5.给委托赋值
 - 6.组合委托
 - 7.为委托添加/移除方法
 - 8.调用委托
 - 9.委托的示例
 - 10.调用带返回值的委托
 - 11.调用带引用参数的委托
 - 12.匿名方法
- 12.1 使用匿名方法
 - 12.2 匿名方法的语法
- 12.2.1 返回类型
 - 12.2.2 参数
 - 12.2.3 params参数
 
 
 - 13.Lambda表达式
 - 14.常见泛型委托
- 14.1 Action
 - 14.2 Func
 - 14.3 Predicate
 
 
 
 - 
 
1.什么是委托
可以认为委托是持有一个或多个方法的对象,此对象可以执行它所“持有”的方法。
delegate void Del(int value);
class Program
{
    static int a = 1;
    static void Up(int v)
    {
        Console.WriteLine($"{a + v}");
    }
    static void Down(int v)
    {
        Console.WriteLine($"{a - v}");
    }
    static void Main()
    {
        Del del1 = new Del(Up);
        Del del2 = new Del(Down);
        del1(1);
        del2(1);
        Console.ReadKey();
    }
output
2 0
2.委托概述
使用委托与类的比较,入下图:
可以把委托看作是包含有序方法列表的对象,这些方法具有相同的签名和返回类型:
- 方法的列表称为调用列表
 - 委托保存的方法可以来自任何类或结构,只有匹配一下两点:
- 委托的返回类型
 - 委托的签名(包括ref和out修饰符)
 
 - 调用列表中的方法可以是实例方法也可以是静态方法
 - 在调用委托时,会执行其调用列表中的所有方法

 
3.声明委托类型
委托类型定义了委托对象调用列表中允许的方法的形式,如下示例代码声明了委托类型:
delegate void MyDel( int x ); // delegate为关键字,void为返回类型,MyDel为委托类型名,int为签名
委托声明与方法声明的不同:
- 以delegate关键字开头
 - 没有方法主体
 - 不需要在类内部声明,因为它是类型声明
 
4.创建委托对象
委托类型的变量声明如下:
MyDel delVar;
有两种创建委托对象的方式,第一种是使用new运算符, new运算符的操作数组成如下:
- 委托类型名
 - 一组圆括号,其中包含作为调用列表中的第一个成员的方法的名字
 
delVar = new MyDel(Class1.Method1);
还可以使用以下快捷语法创建委托对象:
delVar = Class1.Method1;
5.给委托赋值
由于委托时引用类型,可以通过赋值来改变包含在委托变量中的引用,旧的委托对象会被垃圾回收器回收。
MyDel delVar; delVar = Class1.Method1; delVar = Class1.Method2; // Class1.Method1将会被GC
6.组合委托
委托可以调用额外的运算符来“组合”。
MyDel delA = Class1.Method1; MyDel delB = Class1.Method2; MyDel delC = delA + delB; // 组合调用列表
7.为委托添加/移除方法
使用+=运算符为委托添加方法:
MyDel delA = Class1.Method1; // 创建并初始化 delA = Class2.Method2; // 增加方法 delA = StaticClass.StaticMethod; // 增加方法
由于委托是不可变的,所以每添加一个方法其实是创建了一个新的委托。 使用-=运算符为委托移除方法:
delA -= Class2.Method2; // 从委托移除方法
移除一个方法同样是创建了一个新的委托。 移除委托时的注意事项:
- 如果再调用列表中有多个相同的方法,将从列表最后开始搜索,并移除第一个匹配方法
 - 试图删除委托中不存在的方法没有效果
 - 试图调用空委托会抛出异常,若调用列表为空,则委托是null
 
8.调用委托
可以向调用方法一样简单的调用委托。
Mydel delVar = inst.MyM1; delVar += SCl.m3; delVar += X.Act; ... delVar(55);
在使用参数调用委托时会使用相同的参数值(如55)。
9.委托的示例
delegate void PrintFunction();
class Test
{
    public void Print1()
    {
        Console.WriteLine("Print1 -- instance");
    }
    public static void Print2()
    {
        Console.WriteLine("Print2 -- static");
    }
}
class Program
{
    static void Main()
    {
        Test t = new Test();
        PrintFunction pf = t.Print1;
        pf += Test.Print2;
        pf += t.Print1;
        pf += Test.Print2;
        if(null!=pf)
        {
            pf();
        }
        else
        {
            Console.WriteLine("Delegate is empty");
        }
        Console.ReadKey();
    }
}
output
Print1 -- instance Print2 -- static Print1 -- instance Print2 -- static
10.调用带返回值的委托
delegate int MyDel();
class MyClass
{
    int value = 5;
    public int Add2()
    {
        value += 2;
        return value;
    }
    public int Add3()
    {
        value += 3;
        return value;
    }
}
class Program
{
    static void Main()
    {
        MyClass mc = new MyClass();
        MyDel md = mc.Add2;
        md += mc.Add3;
        md += mc.Add2;
        Console.WriteLine($"value = {md()}");
        Console.ReadKey();
    }
}
output
value = 12
最后一个方法执行的返回值是委托的返回值。
11.调用带引用参数的委托
在调用委托列表中的下一个方法时,参数的新值回传给下一个方法
delegate void MyDel(ref int x);
class MyClass
{
    public void Add2(ref int x) { x += 2; }
    public void Add3(ref int x) { x += 3; }
    static void Main()
    {
        MyClass mc = new MyClass();
        MyDel md = mc.Add2;
        md += mc.Add3;
        md += mc.Add2;
        int x = 5;
        md(ref x);
        Console.WriteLine($"value = {x}");
        Console.ReadKey();
    }
}
output
value = 12
12.匿名方法
匿名方法是在初始化委托时内联声明的方法。
12.1 使用匿名方法
- 声明委托变量时作为初始化表达式
 - 组合委托时在赋值语句的右边
 - 为委托增加事件时在赋值语句的右边
 
12.2 匿名方法的语法
匿名方法表达式的语法包含以下组成部分:
- delegate类型关键字
 - 参数列表,无参可省略
 - 语句块,包含匿名方法的代码
 
delegate ( Parameters ) { ImplementationCode }
12.2.1 返回类型
若委托的返回类型为int,则匿名方法中也应返回int。
delegate int Del(int n);
static void Main()
{
    Del d = delegate(int x) { return x + 20; } // 返回一个整型值
}
12.2.2 参数
除了数组参数,匿名方法的参数列表必须与委托有以下匹配:
- 参数数量
 - 参数类型及位置
 - 修饰符 以下两个情况都满足可以简化匿名方法的参数列表:
 - 委托的参数列表不包含任何out参数
 - 匿名方法不使用任何参数
 
delegate void Del(int x);
Del d = delegate
        {
            PrintMessage();
            CleanUp();
        };
12.2.3 params参数
如果委托声明的参数列表包含params参数,那么匿名方法的参数列表将忽略params关键字:
delegate void Del(int x, params in[] y);
Del d = delegate(int x, int[] y){...};
delegate void MyDel(int x, params int[] y);
class MyClass
{
    static void Main()
    {
        MyDel md = delegate (int x, int[] y)
        {
            foreach(var i in y)
            {
                Console.WriteLine(i);
            }
        };
        md(1, 2, 3, 4);
        Console.ReadKey();
    }
}
output
2 3 4
13.Lambda表达式
使用Lambda表达式创建委托:
MyDel del = delegate(int x) {return x + 1;}; // 匿名方法
MyDel newdel = (int x) => {return x + 1;}; // Lambda表达式
Lambda表达式的简化规则:
- 编译器可从委托声明中得到委托参数的类型(ref和out参数须注明类型)
- 带有类型的参数列表称为显示类型
 - 省略类型的参数列表称为隐式类型
 
 - 如果只有一个隐式类型参数,则可以省略圆括号
 - Lambda允许表达式主体是语句块或表达式 Lambda表达式的语法演示如下:
 
| (参数,参数) (参数) 参数 ()  | => | {语句} 表达式  | 
|---|
Lambda表达式的语法由Lambda运算符和左边的参数部分以及右边的Lambda主体构成。
14.常见泛型委托
14.1 Action
Action<>委托可以拥有n个参数(0-16),无返回值。
class Program
{
    static void Method1()
    {
        Console.WriteLine("without any parameter");
    }
    static void Method2(int i)
    {
        Console.WriteLine($"the int is {i}");
    }
    static void Method3(string s, double d)
    {
        Console.WriteLine($"the string is {s}, the double is {d}");
    }
    static void Main()
    {
        Action A1 = Method1;
        Action<int> A2 = Method2;
        Action<string, double> A3 = Method3;
        A1();
        A2(1);
        A3("hello", 3.14);
        Console.ReadKey();
    }
}
output
without any parameter the int is 1 the string is hello, the double is 3.14
14.2 Func
Func<>委托可以拥有n个参数(1-16),类型参数中的最后一个作为返回值类型。因此类型参数不能为空,至少有一个返回类型。
class Program
{
    static int Method1(int i)
    {
        return i * 10;
    }
    static string Method2(int a, double d)
    {
        return (a + d).ToString();
    }
    static void Main()
    {
        Func<int, int> F1 = Method1;
        Func<int, double, string> F2 = Method2;
        Console.WriteLine($"{F1(10)}");
        Console.WriteLine($"{F2(1, 3.14)}");
        Console.ReadKey();
    }
}
output
100 4.14
14.3 Predicate
Predicate<>委托拥有一个参数,其返回值为bool型。
class Program
{
    static bool Method(int i)
    {
        return i > 0 ? true : false;
    }
    static void Main()
    {
        Predicate<int> P = Method;
        Console.WriteLine(P(10));
        Console.ReadKey();
    }
}
output
True
通过匿名方法使用Predicate<>,
class Program
{
    static void Main()
    {
        var anomynous = new Predicate<int>(delegate (int i) { return i > 0 ? true : false; });
        Console.WriteLine(anomynous(1));
        Console.ReadKey();
    }
}
output
True
来源:https://www.cnblogs.com/jizhiqiliao/p/10649160.html
