为什么要使用委托呢?委托是将方法作为参数进行传递,简化了代码
一、委托的声明和实例化
public class TestDelegate
{
public delegate int GetValueDelegate(int x, int y);//声明一个委托类型
public int GetValue(GetValueDelegate getValueDelegate, int x, int y)//将委托类型的实例当作方法的形参
{
return getValueDelegate(x, y);//调用委托
}
}
public partial class Form1 : Form
{
TestDelegate.GetValueDelegate getValueDelegate;//定义一个委托类型的引用
private int GetMax(int x, int y)
{
return x > y ? x : y;
}
private int GetMin(int x, int y)
{
return x < y ? x : y;
}
public Form1()
{
InitializeComponent();
getValueDelegate = GetMax;//使用方法直接实例化委托,获取最大值
//getValueDelegate =new TestDelegate.GetValueDelegate( GetMax);//也可以这样实例化委托
TestDelegate testDelegate = new TestDelegate();
int value = testDelegate.GetValue(getValueDelegate, 100, 200);
}
}
二、Lambda表达式
1)语句Lambda
在上面的程序中我们看到,如果要实例化一个委托,则需要定义一个方法,语句Lambda的作用就是就是我们使用一个特殊的形式去描述一个方法,而不是直接定义一个全新的方法,如下:
旧的使用形式:
int value = testDelegate.GetValue(getValueDelegate, 100, 200);
1、 新的使用形式:
int value = testDelegate.GetValue((int x,int y)=> { return x > y ? x : y; }, 100, 200);
2、如果可以推断类型的话,还可以将参数列表中的x,y的类型省略,如下:
int value = testDelegate.GetValue(( x, y)=> { return x > y ? x : y; }, 100, 200);
3、如果遇到只有一个参数的情况
public class TestDelegate
{
public void GetValue(Action<int> getValueDelegate, int x)
{
getValueDelegate(x);
}
}
public Form1()
{
InitializeComponent();
TestDelegate testDelegate = new TestDelegate();
testDelegate.GetValue( x=> { Console.WriteLine(x); },100);//可以直接将形参列表的圆括号去除了
}
4、如果没有参数,则如下:
public class TestDelegate
{
public void GetValue(Action getValueDelegate)
{
getValueDelegate();
}
}
public Form1()
{
InitializeComponent();
TestDelegate testDelegate = new TestDelegate();
testDelegate.GetValue( ()=> { Console.WriteLine("我没有参数"); });//直接用了一个空的圆的括号
}
2)表达式Lambda
表达式Lambda将语句Lambda中的大括号以及return语句都直接省略了,如下:
public class TestDelegate
{
public int GetValue(Func <int,int> getValueDelegate,int x)
{
return getValueDelegate(x);
}
}
public Form1()
{
InitializeComponent();
TestDelegate testDelegate = new TestDelegate();
testDelegate.GetValue( x=> x+1 ,100);//return关键字,大括号都没了
}
三、Action和Func
如果我们总是自定义委托就比较麻烦,所以c#为我们提供了Action和Func这两个委托类型,注意以下三点:
1)Action是没有返回值的委托类型;
2)Func是有返回值的委托类型;
3)可以声明Action或者Func的委托类型数组;
4)委托没有结构相等性,即不能将委托类型的对象引用转换成不相关的委托类型,唯一的办法是通过Invoke方法去调用旧委托的方法
Action action1 = () => Console.WriteLine(“我是无参委托1”);
Action action2 = () => Console.WriteLine(“我是无参委托2”);
action2 = action1.Invoke;
action2();
5)委托的逆变性
Action action3 = ( str) => Console.WriteLine(str);
Action action4 = (obj) => Console.WriteLine(obj);
action3 = action4;//逆变
6)委托的协变性
Func func1=()=> “1”;
Func func2=()=> 100;
func2 = func1;//协变
四、外部变量
c#5.0之前输出是3,3,3,C#5.0输出1,2,3,参考c#本质论,但是自己实验发现好像都是1,2,3
var items = new string[] { "1", "2", "3" };
var actions = new List<Action>();
foreach (string item in items )
{
actions.Add(()=> { Console.WriteLine(item); });
}
foreach (Action action in actions )
{
action();
}
对于上述代码,item就是一个外部变量
五、表达式树