基础拾遗:
前言:
C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。委托(Delegate)特别用于实现事件和回调方法。所有的委托都派生自 System.Delegate 类。把一个方法当作参数传递,让其它方法进行调用执行。
1.委托的声明
委托声明决定了可由该委托引用的方法。委托可指向一个与其具有相同标签的方法。
1.1.delegate
1.1.1. 0-23个参数,可以有返回值也可以没有返回值
public delegate int MyDelegateEventHandler (string parm);
注:(1).此委托指向的方法必须是参数为string类型,返回类型为int类型的。其他声明类比所得。
(2).EventHandler是c# 命名规范,当然我理解规范就是可以随意啦。
(3).委托调用时必须判断是否为null不然会报异常
(4).事件也是一种委托
1.1.2.委托的调用
MyDelegateEventHandler fun=new MyDelegateEventHandler(method); or MyDelegateEventHandler fun=method; // fun不为空,则调用回调方法 if (fun!= null) { fun(val); } //fun?.Invoke(val); 简化版本调用
1.1.3.委托的多播
每个委托都只包含一个方法调用,如果调用多个方法,就需要多次显示调用这个委托。如果同一个委托调用多个方法,我们就可以用多播委托
public delegate void MyDelegate ();
public voidMyMethod()
{
//#
}
public void MyMethod1()
{
//#
}
public void MyMethod2()
{
//#
}
MyDelegateEnventHander myDelegate;
myDelegate=new MyDelegateEventHander(MyMethod);
myDelegate+=new MyDelegateEventHander(MyMethod1);
...........
//调用
myDelegate();
注:
1.委托对象可使用 "+" 运算符进行合并;
2."-" 运算符可用于从合并的委托中移除组件委托;
3.委托指定方法类型必须一致;
4.返回类型一般为void,但非必须;
5.GetInvocationList获取委托索引
if (MyDelegate != null) System.Delegate[] dels = MyDelegate .GetInvocationList(); for (int i = 0; i < dels.Length; i++) { MyDelegate -= dels[i] as MethodDelegate; }
以上是利用GetInvocationList获取委托索引的一个简单应用。
1.2.Action
Action至少0个参数,至多16个参数,无返回值。
Action 表示无参,无返回值的委托 Action<int,string> 表示有传入参数int,string无返回值的委托 Action<int,string,bool> 表示有传入参数int,string,bool无返回值的委托 Action<int,int,int,int> 表示有传入4个int型参数,无返回值的委托
public void Test<T>(Action<T> action,T p) { action(p); }
1.3.Func
Func至少0个参数,至多16个参数,根据返回值泛型返回。必须有返回值,不可void
Func是无返回值的泛型委托 Func<int> 表示无参,返回值为int的委托 Func<object,string,int> 表示传入参数为object, string 返回值为int的委托 Func<object,string,int> 表示传入参数为object, string 返回值为int的委托 Func<T1,T2,,T3,int> 表示传入参数为T1,T2,,T3(泛型)返回值为int的委托
1.4.predicate
1.4.1.predicate 是返回bool型的泛型委托;
1.4.2.predicate<int> 表示传入参数为int 返回bool的委托;
1.4.3.Predicate有且只有一个参数,返回值固定为bool;
public delegate bool Predicate<T> (T obj)
2.委托的实例化
2.1.delegate
public delegate int MyDelegateEventHandler (string parm) public int MyMethod(string parm) { //# } MyDelegateEventHandler MyDelegate=new MyDelegateEventHandler(MyMethod)
注:委托实例化的时候,委托对象必须使用 new 关键字来创建,且与一个特定的方法有关。委托参数中的方法不含参数。
2.2.Action的使用
public void Test<T>(Action<T> action, T p) { action(p); } private void Action(string s) { # } //调用 Test<string>(Action,"wyl");
2.3.Func的使用
public int Test<T1, T2>(Func<T1, T2, int> func, T1 a, T2 b) { return func(a, b); } private int Fun(int a, int b) { # } //调用 Test<int,int>(Fun,100,200)
2.4 委托实现冒泡排序
//定义对象 class Student { public string Name { get; private set; } public decimal Scores{ get; private set; } public Student(string name, decimal scores) { this.Name = name; this.Scores= scores; } public override string ToString() { return string.Format("{0},{1:C}",Name,Scores); } public static bool CompareScores(Student e1,Student e2) { return e1.Scores< e2.Scores; } } //利用委托实现冒泡 class BubbleScores { public static void Sort<T>(IList<T> sortArray, Func<T, T, bool> comparison) { bool swapped = true; do { swapped = false; for (int i = 0; i < sortArray.Count - 1; i++) { if (comparison(sortArray[i + 1], sortArray[i])) { T temp = sortArray[i]; sortArray[i] = sortArray[i + 1]; sortArray[i + 1] = temp; swapped = true; } } } while (swapped); } } //调用 Student[] students={new Student("wyl", 100),#}; BubbleSorter.Sort(students, Student.CompareScores); foreach(var student in students) Console.WriteLine(student);
3.匿名函数与lambda
3.1什么是匿名函数
匿名函数是一个“内联”语句或表达式,可在需要委托类型的任何地方使用。
可以使用匿名函数来初始化命名委托(无需取名字的委托),或传递命名委托(而不是命名委托类型,传递一个方法块,而不是委托类型)[callback的方式]作为方法参数。
MyDelegate funDelegate = delegate(string s) { Console.WriteLine(s); }; funDelegate ("this is anonymous delegate");
3.2.lambda
lambda表达式实际上是一个匿名函数。编译器在看到lambda之后会在类中自动定义一个新的私有方法。lambda必须匹配委托!其中lambda是从c#3.0后引用的
lambda的语法:
参数 => 方法体。
=>左边是要传入的参数,本例中是传入一个Int类型的变量,=>右边是具体的代码。
//如果不传递参数: ()=>Console.WriteLine("Hello World!") //传递一个参数: (int n)=>Console.WriteLine(n.ToString()) //或者去掉()和int 编译器会自己推断类型: n=>Console.WriteLine(n.ToString()) //传递多个参数: (int n ,int m)=>Console.WriteLine(n+m) //或者编译器自己推断类型: (n , m)=>Console.WriteLine(m+n)
4.事件
4.1 什么是事件
事件是以委托为基础也可以说就是一种委托,事件能实现的委托都能实现。他们的区别在于事件只能在方法内使用。
/// <summary> /// 声明委托 /// </summary> public delegate void EventHander(string a); /// <summary> /// 声明委托相关的事件 /// </summary> public event EventHander EventMain;
4.2.猫和老鼠
4.2.1猫的定义
/// <summary> /// 猫类 /// </summary> class Cat { public string Name { get; private set; } public string Color { get; private set; } public delegate void CatComeEventHandler(); public event CatComeEventHandler CatComeEvent;//声明“猫来了”的事件 public Cat(string name,string color) { this.Name = name; this.Color = color; } public void CatCome() { Console.WriteLine(Color+"的猫,名字叫:"+Name+",跑过来了。。。"); CatComeEvent();//触发“猫来了”的事件 }
4.2.2.老鼠的定义
/// <summary> /// 老鼠类 /// </summary> class Mouse { public string Name { get; private set; } public string Color { get; private set; } public Mouse(string name,string color,Cat cat) { this.Name = name; this.Color = color; cat.CatComeEvent += this.MouseRun;//订阅“猫来了”的事件,并做出反应,老鼠逃跑 MouseRun } public void MouseRun() { Console.WriteLine(Color + "的" +Name+"老鼠,逃跑了"); } }
4.2.3.猫来了老鼠跑
static void Main(string[] args) { Cat Tom = new Cat("汤姆", "蓝色"); Mouse Jerry = new Mouse("杰瑞", "灰色",Tom); Mouse Jack = new Mouse("杰克", "黑色",Tom); //Tom.CatComeEvent += new Cat.CatComeEventHandler(Jerry.MouseRun); //Tom.CatComeEvent+= new Cat.CatComeEventHandler(Jack.MouseRun); //Tom.CatComeEvent+= Jerry.MouseRun; //Tom.CatComeEvent += Jack.MouseRun; Tom.CatCome(); Console.ReadKey(); }