委托是 函数(方法)的容器
可以理解为表示函数(方法)的变量类型
用来 存储、传递函数(方法)
委托的本质是一个类,用来定义函数(方法)的类型(返回值和参数的类型)
不同的 函数(方法)必须对应和各自"格式"一致的委托
关键字 : delegate
语法:访问修饰符 delegate 返回值 委托名(参数列表);写在哪里?
可以申明在namespace和class语句块中
更多的写在namespace中简单记忆委托语法 就是 函数申明语法前面加一个delegate关键字
访问修饰符默认不写 为public 在别的命名空间中也能使用
private 其他命名空间就不能用了
一般使用public
申明了一个可以用来存储无参无返回值的容器
这里只是定义了规则 并没有使用
delegate void MyFun();
委托规则的申明 是不能重名(同一语句块中)
表示用来装载或传递 返回值为 int 有一个 int参数 的函数的 委托 容器
delegate int MyFun2(int a);
- class Program
- {
- static void Main(string[] args)
- {
- Console.WriteLine("委托");
-
- //专门用来装载 函数的 容器
- MyFun f = new MyFun(Fun);
- Console.WriteLine("1");
- Console.WriteLine("2");
- Console.WriteLine("3");
- Console.WriteLine("4");
- Console.WriteLine("5");
- f.Invoke(); //1 2 3 4 5 123456
-
- MyFun f2 = Fun;
- Console.WriteLine("1");
- Console.WriteLine("2");
- Console.WriteLine("3");
- Console.WriteLine("4");
- Console.WriteLine("5");
- f2(); //1 2 3 4 5 123456
-
- MyFun2 f3 = Fun2;
- f3(1);
- Console.WriteLine(f3(1)); //1
-
- MyFun2 f4 = new MyFun2(Fun2);
- Console.WriteLine(f4.Invoke(3)); //3
- }
- static void Fun()
- {
- Console.WriteLine("123456");
- }
- static int Fun2(int value)
- {
- return value;
- }
- }
委托是支持 泛型的 可以让返回值和参数 可变 更方便我们的使用
delegate T MyFun3
委托变量是函数的容器
委托常用在:
- class Test
- {
- public MyFun fun;
- public MyFun2 fun2;
-
- public void TestFun(MyFun fun, MyFun2 fun2)
- {
- //先处理一些别的逻辑 当这些逻辑处理完了 再执行传入的函数
- int i = 1;
- i *= 2;
- i += 2;
-
- //fun();
- //fun2(i);
- //this.fun = fun;
- //this.fun2 = fun2;
- }
-
- #region 增
- public void AddFun(MyFun fun, MyFun2 fun2)
- {
- this.fun += fun;
- this.fun2 += fun2;
- }
- #endregion
-
- #region 删
- public void Remove(MyFun fun, MyFun2 fun2)
- {
- //this.fun = this.fun - fun;
- this.fun -= fun;
- this.fun2 -= fun2;
- }
- }
- //如何用委托存储多个函数
- MyFun ff = null;
- //ff = ff + Fun;
- ff += Fun;
- ff += Fun3;
- ff();
- //从容器中移除指定的函数
- ff -= Fun;
- //多减 不会报错 无非就是不处理而已
- ff -= Fun;
- ff();
- //清空容器
- ff = null;
- if( ff != null )
- {
- ff();
- }
使用系统自带委托 需要引用 using System;
- //无参无返回值
- Action action = Fun;
- action += Fun3;
- action();
-
- //可以指定返回值类型的 泛型委托
- Func<string> funString = Fun4;
- Func<int> funInt = Fun5;
-
- //可以传n个参数的 系统提供了 1到16个参数的委托
- Action<int, string> action1 = Fun6;
-
- //可以传n个参数的 并且有返回值的 系统也提供了 16个委托
- Func<int, int> func2 = Fun2;
-
- //***************************************************//
- static string Fun4()
- {
- return " ";
- }
- static int Fun5()
- {
- return 1;
- }
- static void Fun6(int i, string s)
- {
-
- }
简单理解 委托 就是装载、传递函数的容器而已
可以用委托变量 来存储函数或者传递函数的
系统其实已经提供了很多委托给我们用
Action :没有返回值,参数 提供了 0到16个委托给我们用
Func :有返回值,参数 提供了0到16个委托给我们用
事件是基于委托的存在
事件是委托的安全包裹
让委托的使用更具有安全性
事件 是一种特殊的变量类型
申明语法:
访问修饰符 event 委托类型 事件名;
事件的使用:
1.事件是作为 成员变量存在于类中
2.委托怎么用 事件就怎么用
事件相对于委托的区别:
1.不能在类外部 赋值
2.不能再类外部 调用
注意:它只能作为成员存在于类和接口以及结构体中
- class Test
- {
- //委托成员变量 用于存储 函数的
- public Action myFun;
- //事件成员变量 用于存储 函数的
- public event Action myEvent;
-
- public Test()
- {
- //事件的使用和委托 一模一样 只是有些 细微的区别
- myFun = TestFun;
- myFun += TestFun;
- myFun -= TestFun;
- myFun();
- myFun.Invoke();
- //myFun = null;
-
- myEvent = myFun;
- myEvent += myFun;
- myEvent -= myFun;
- myEvent();
- myEvent.Invoke();
- //myEvent = null;
- }
- public void TestFun()
- {
- Console.WriteLine("123");
- }
- }
-
- class Program
- {
- static void Main(string[] args)
- {
- Console.WriteLine("事件");
-
- Test t = new Test();
-
- //委托可以在外部赋值
- t.myFun = null;
-
- //事件不能在外部赋值
- //t.myEvent = null;
- //虽然不能直接赋值 但是可以 加减 去添加移除记录的函数
- t.myEvent += TestFun;
-
- //委托是可以在外部调用的
- t.myFun();
- t.myFun.Invoke();
-
- //事件不能在外部调用
- //t.myEvent();
- //t.myEvent.invoke();
- //只能在类的内部去封装 调用
-
- Action a = TestFun;
- //event Action e = TestFun;
- //事件 是不能作为临时变量在函数中使用的
- }
- static void TestFun()
- {
- Console.WriteLine("123");
- }
- }
事件和委托的区别
事件和委托的使用基本是一模一样的
事件就是特殊的委托
主要区别:
顾名思义,就是没有名字的函数
匿名函数的使用主要是配合委托和事件进行使用
脱离委托和事件 是不会使用匿名函数的
delegate (参数列表)
{
//函数逻辑
};
何时使用?
1.函数中传递委托参数时
2.委托或事件赋值时
- Action a= delegate ()
- {
- Console.WriteLine("匿名函数逻辑");
- };
- a();
- Action<int,string>b= delegate (int a, string b)
- {
- Console.WriteLine(a);
- Console.WriteLine(b);
- };
- b(100,"123");
- Func<string> c= delegate ()
- {
- return "123";
- };
- Console.WriteLine(c());
- Test t = new Test();
- Action ac = delegate ()
- {
- Console.WriteLine("随参数传入的匿名函数逻辑");
- };
- t.Dosomething(50, ac);
- // 参数传递
- t.Dosomething(100, delegate ()
- {
- Console.WriteLine("随参数传入的匿名函数逻辑");
- });
-
- // 返回值
- Action ac2 = t.GetFun();
- ac2();
- //一步到位 直接调用返回的 委托函数
- t.GetFun()();
添加到委托或事件中后 不记录 无法单独移除
- Action ac3 = delegate ()
- {
- Console.WriteLine("匿名函数一");
- };
- ac3+= delegate ()
- {
- Console.WriteLine("匿名函数二");
- };
- ac3();
- //因为匿名函数没有名字 所以没有办法指定移除某一个匿名函数
- //此匿名函数非彼匿名函数 不能通过看逻辑是否一样 就证明是一个
- //ac3 -= delegate ()
- //{
- // Console.WriteLine("匿名函数一");
- //};
- ac3 = null;
- //ac3();
匿名函数 就是没有名字的函数
固定写法:
delegate (参数列表){}
主要是在 委托传递和存储时 为了方便可以直接使用倪敏该函数
缺点是 没有办法指定移除
可以将lambad表达式 理解为匿名函数的简写
它除了写法不同外
使用上和匿名函数一模一样
都是和委托或者事件 配合使用的
匿名函数
delegate (参数列表)
{};
lambad表达式
(参数列表) =>
{
//函数体
};
- Action a = () =>
- {
- Console.WriteLine("无参无返回值的lambad表达式");
- };
- a();
- Action<int>a2= (int value) =>
- {
- Console.WriteLine("有参数的lambda表达式{0}",value);
- };
- a2(100);
-
- Action<int> a3 = (value) =>
- {
- Console.WriteLine("省略参数类型的写法{0}", value);
- };
- a3(200);
- Func<string, int> a4 = (value) =>
- {
- Console.WriteLine("有返回值有参数的lambda表达式{0}", value);
- return 1;
- };
-
- //其他传承使用的和匿名函数一样
- //确定也是和匿名函数一样的
内层的函数可以引用包含在它外层的函数的变量
即使外层函数的执行已经终止
注意:该变量提供的值并非变量创建时的值,而是在父函数范围内的最终值
- class Test
- {
- event Action action;
- public Test()
- {
- int value = 10;
- //这里就形成了闭包
- //因为 当构造函数执行完毕时 其中什么的临时变量value的生命周期被改变了
- action = () =>
- {
- Console.WriteLine(value);
- };
- for (int i = 0; i < 10; i++)
- {
- //此index 非彼index
- int index = i;
- action += () =>
- {
- Console.WriteLine(index);
- };
- }
- }
- public void DoSomething()
- {
- action();
- }
- }
匿名函数的特殊写法 就是 lambad表达式
固定写法 就是(参数列表) =>{}
参数列表 可以直接省略参数类型
主要在 委托传递和存储时 为了方便可以直接使用匿名函数或者lambad表达式
缺点:无法指定移除