委托是一种可以指向方法的数据类型,可以声明委托类型变量。
声明委托的方式:delegate 返回值类型 委托类型名(参数)
比如:delegate void MyDel(int i);
注意这里的除了前面的delegate,剩下部分和声明一个函数一样,但是MyDel不是函数名,而是委托类型名。
如何创建委托类型的对象:
MyDel sp = new MyDel (SayHello); //SayHello需要和MyDel的参数返回值一样;sp这个委托变量就指向SayHello这个方法。
注意不要写成new Mydel (SayHello())因为加上()就是调用方法了。
简化的方法:MyDel sp = SayHello;
编译器会给搞成new Mydel(SayHello),反编译看看。注意不要写成MyDel sp = SayHello();
委托的使用:委托变量之间可以互相赋值,就是一个传递指向方法的过程;sp()就是调用指向的方法,如果有参数就传递参数。
委托是引用类型,可以为null,如果委托变量是null,那么如果调用的话,就会抛出NullReferenceException。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
namespace NS
{
public delegate void MyDel1(int i);
public delegate int MyDel2(int i, string s);
public delegate string MyDel3();
internal class Program
{
static void Main(string[] args)
{
不能写成new MyDel(M1()); 因为()代表调用方法
//MyDel1 d1 = new MyDel1(M1); //声明一个MyDel类型的变量d1,new MyDel(M1)创建一个指向M1方法的委托对象。
//Console.WriteLine(d1);
//d1(10); //调用d1指向的方法
//MyDel2 d2 = new MyDel2(M2);
//int i1 = d2(10, "abc");
//Console.WriteLine("i1 = " + i1);
//MyDel3 d3 = new MyDel3(M3);
//Console.WriteLine(d3);
//Console.WriteLine(d3()); //加括号和不加括号的区别!
//d3 = new MyDel3(M4);
MyDel3 d3 = M3; //等价于MyDel3 d3 = new MyDel3(M3);
Console.WriteLine(d3());
Console.ReadLine();
}
static void M1(int i)
{
Console.WriteLine("i = " + i);
}
static int M2(int i, string str)
{
return i + 10;
}
static string M3()
{
return "M3";
}
static string M4()
{
return "M4";
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
namespace NS
{
delegate bool CompareFunc(object obj1, object obj2);
internal class Program
{
static void Main(string[] args)
{
//int[] objs = new int[] { 1, 2, 4, 4, 2, 1, 2, 3 }; //int[]无法直接转换为object[]
//object[] objs = { 1, 2, 4, 4, 2, 1, 2, 3 };
object[] objs = { 1.1, 2.2, 4.3, 4.4, 2.5, 1.6, 2.7, 3.8 };
//object o1 = GetMax(objs, CompareInt);
object o1 = GetMax(objs, new CompareFunc(Compare));
Console.WriteLine(o1);
Person p1 = new Person();
p1.Name = "lilei";
p1.Age = 10;
Person p2 = new Person();
p2.Name = "hanmeimei";
p2.Age = 20;
Person p3 = new Person();
p3.Name = "polly";
p3.Age = 30;
Person[] sites = new Person[] { p1, p2, p3 };
object obj1 = GetMax(sites, ComparePerson);
Person person = obj1 as Person;
Console.WriteLine(person.ToString()) ;
Console.ReadLine();
}
static bool Compare(object obj1, object obj2)
{
dynamic first = obj1, second = obj2;
return first > second;
}
static bool ComparePerson(object obj1, object obj2)
{
Person p1 = obj1 as Person;
Person p2 = obj2 as Person;
return p1.Age > p2.Age;
}
static object GetMax(object[] nums, CompareFunc func)
{
object max = nums[0];
for (int i = 0; i < nums.Length; i++)
{
if (func(nums[i], max))
{
max = nums[i];
}
}
return max;
}
}
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
{
return "Name = " + Name + ", Age = " + Age;
}
}
}
namespace NS
{
delegate T MyDel<T>(T t);
internal class Program
{
static void Main(string[] args)
{
MyDel<int> mydel1 = Func1;
Console.WriteLine(mydel1(20));
Console.ReadLine();
}
static int Func1(int i)
{
return i + 10;
}
}
}
.Net中内置两个泛型委托Func、Action(在“对象浏览器”的mscorlib的System下),日常开发中基本不用自定义委托类型了。
Func是有返回值的委托;Action是没有返回值的委托。
测试一下用Func、 Action代替之前的委托。
namespace NS
{
//delegate void Dele1();
internal class Program
{
static void Main(string[] args)
{
//Dele1 d1 = Func1;
Action action1 = Func1;
action1();
Func<int, int, bool> func1 = CompareInt;
Console.WriteLine(func1(3, 5));
Console.ReadLine();
}
static void Func1()
{
Console.WriteLine("Func1");
}
static bool CompareInt(int i1, int i2)
{
return i1 > i2;
}
}
}
使用Delegate的时候很多时候没必要使用一个普通的方法,因为这个方法只有这个Delegate会用,并且只用一次,这时候使用匿名方法最合适。
匿名方法就是没有名字的方法。定义语法:MyDelegate p = delegate(int s){s=10;};
使用匿名方法改造GetMax方法:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
namespace NS
{
delegate bool Mydele1(int i, string s);
delegate bool CompareFunc(object obj1, object obj2);
internal class Program
{
static void Main(string[] args)
{
Mydele1 d1 = Func1;
Mydele1 d2 = delegate (int i, string str)
{
Console.WriteLine("i = " + i + ", str = " + str);
return true;
};
bool b1 = d2(5, "lilei");
Console.WriteLine(b1);
object[] objs = new object[] { 1, 2, 4, 4, 2, 1, 2, 3 }; //int[]无法直接转换为object[]
CompareFunc f1 = delegate (object obj1, object obj2)
{
dynamic first = obj1, second = obj2;
return first > second;
};
object obj = GetMax(objs, f1);
Console.WriteLine(obj);
Console.ReadLine();
}
static bool Func1(int i, string str)
{
Console.WriteLine("i = " + i + ", str = " + str);
return true;
}
static object GetMax(object[] nums, CompareFunc func)
{
object max = nums[0];
for (int i = 0; i < nums.Length; i++)
{
if (func(nums[i], max))
{
max = nums[i];
}
}
return max;
}
}
}
函数式编程,在Entity framework编程中用的很多
1、Action a1 = delegate(int i) { Console.WriteLine(i); };
可以简化成(=>读作goes to)
Action a2 = (int i) => { Console.WriteLine(i); };
2、可以省略参数类型(编译器会自动根据委托类型推断)。
Action a3 = (i) => { Console.WriteLine(i); };
如果只有一个参数还可以省略参数的小括号(多个参数不行)
Action a4 = i => { Console.WriteLine(i); };
3、如果委托有返回值,并且方法体只有一行代码,这一行代码还是返回值,那么就可以连方法的大括号和return都省略:
Func
Func
4、普通匿名类型也是一样用lambda表达式。
internal class Program
{
static void Main(string[] args)
{
Action<int> a1 = delegate (int i) { Console.WriteLine(i); };
Action<int> a2 = (int i) => { Console.WriteLine(i); };
Action<int> a3 = i => { Console.WriteLine(i); };
Func<string, int, bool> f1 = delegate (string s, int i) { return true; };
Func<string, int, bool> f2 = (string s, int i) => { return true; };
Func<string, int, bool> f3 = (s, i) => { return true; };
Func<string, int, bool> f4 = (s, i) => true;
Console.ReadLine();
}
}
namespace NS
{
internal class Program
{
static void Main(string[] args)
{
int[] nums = new int[] { 1, 2, 4, 4, 2, 1, 2, 3 };
//int i_max = GetMax(nums, CompareInt);
//int i_max = GetMax(nums, delegate (int i1, int i2) { return i1 > i2; });
int i_max = GetMax(nums, (i1, i2) => i1 > i2);
Console.WriteLine(i_max);
Person p1 = new Person();
p1.Name = "lilei";
p1.Age = 10;
Person p2 = new Person();
p2.Name = "hanmeimei";
p2.Age = 20;
Person p3 = new Person();
p3.Name = "polly";
p3.Age = 30;
Person[] sites = new Person[] { p1, p2, p3 };
Person p = GetMax<Person>(sites, (p1, p2) => p1.Age > p2.Age);
Console.WriteLine(p);
Console.ReadLine();
}
static bool CompareInt(int i1, int i2)
{
return i1 > i2;
}
static T GetMax<T>(T[] objs, Func<T, T, bool> compareFunc)
{
T max = objs[0];
for (int i = 0; i < objs.Length; i++)
{
if (compareFunc(objs[i], max))
{
max = objs[i];
}
}
return max;
}
}
class Person
{
public Person()
{
}
public Person(string name, int age)
{
Name = name;
Age = age;
}
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
{
return "Name = " + Name + ", Age = " + Age;
}
}
}
namespace NS
{
internal class Program
{
static void Main(string[] args)
{
int[] nums = new int[] { 1, 2, 4, 4, 2, 1, 2, 3 };
//IEnumerable list = nums.MyWhere(i => i > 2);
IEnumerable<int> list = nums.MyWhere(i => i % 2 == 0);
foreach (var item in list)
{
Console.WriteLine(item);
}
string[] strs = new string[] { "tom", "jim", "lily", "hanmeimei" };
foreach (var name in strs.MyWhere(s => s.Contains("m")))
{
Console.WriteLine(name);
}
Console.ReadLine();
}
}
public static class JiHeExt
{
public static IEnumerable<T> MyWhere<T>(this IEnumerable<T> data, Func<T, bool> func)
{
List<T> resultList = new List<T>();
//foreach()面试题:什么样的对象可以使用foreach遍历?
//实现了IEnumreable接口。List,数组等都实现了IEnumerable接口
foreach (var item in data)
{
if (func(item))
{
resultList.Add(item);
}
}
return resultList;
}
}
}
Where(支持委托):是对数据按照lambda表达式进行过滤。
Select(支持委托):是对集合中的数据进行处理,生成一个新的集合,集合长度和原始集合长度一致。
Max、Min、Sum、Average
OrderBy
namespace NS
{
internal class Program
{
static void Main(string[] args)
{
List<int> list = new List<int>() { 3, 9, 8, 16, 90 };
//IEnumerable data = list.Where(x => x > 10);
//IEnumerable data = list.Select(x => x * 10);
IEnumerable<string> data = list.Select(x => "hello: " + x);
Console.WriteLine(data.GetType()); //返回实现该接口的类
foreach (var item in data)
{
Console.WriteLine(item);
}
int max = list.Max();
int min = list.Min();
int sum = list.Sum();
double average = list.Average();
Console.WriteLine("max = " + max + ", min = " + min + ", sum = " + sum + ", average = " + average);
Console.WriteLine("====================================");
foreach (var item in list.OrderBy(i => i))
{
Console.WriteLine(item);
}
Console.WriteLine("====================================");
Person p3 = new Person();
p3.Name = "polly";
p3.Age = 30;
Person p1 = new Person();
p1.Name = "lilei";
p1.Age = 10;
Person p2 = new Person();
p2.Name = "hanmeimei";
p2.Age = 20;
Person[] sites = new Person[] { p1, p2, p3 };
int age_sum1 = sites.Sum(p => p.Age);
int age_sum2 = sites.MySum(p => p.Age);
int age_sum3 = sites.MySum(p => p.Name.Length);
Console.WriteLine(age_sum1);
Console.WriteLine(age_sum2);
Console.WriteLine(age_sum3);
//foreach (var item in sites.OrderBy(p => p.Age))
foreach (var item in sites.OrderBy(p => p.Name.Length))
{
Console.WriteLine(item);
}
List<Person> ps1 = sites.OrderBy(p => p.Age).ToList();
Person[] ps2 = sites.OrderBy(p => p.Age).ToArray();
List<Person> ps3 = sites.ToList();
Person[] ps4 = ps3.ToArray();
Console.ReadLine();
}
}
class Person
{
public Person()
{
}
public Person(string name, int age)
{
Name = name;
Age = age;
}
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
{
return "Name = " + Name + ", Age = " + Age;
}
}
public static class MyEx
{
public static int MySum<T>(this IEnumerable<T> data, Func<T, int> func)
{
int sum = 0;
foreach (var item in data)
{
sum += func(item);
}
return sum;
}
}
}
First:获取第一个,如果一个都没有则异常
FirstOrDefault:获取第一个,如果一个都没有则返回默认值
Single:获取唯一一个,如果没有或者有多个则异常
SingleOrDefault:获取唯一一个,如果没有则返回默认值,如果有多个则异常
ToList、ToArray
namespace NS
{
internal class Program
{
static void Main(string[] args)
{
string[] strs1 = { };
string[] strs2 = { "lilei" };
string[] strs3 = { "lilei", "hanmeimei" };
List<int> list1 = new List<int>();
//int i = list1.First();
Console.WriteLine(list1.FirstOrDefault());
//string s1 = strs1.First(); //获取集合中的第一个元素,如果一个元素都没有,则抛异常
Console.WriteLine(strs2.First());
string s1 = strs1.FirstOrDefault(); //获取集合中的第一个元素,如果一个元素都没有,则返回类型的默认值
string s2 = strs2.Single(); //获取集合中的唯一一个元素,如果没有元素或者有不止一个元素,则抛异常
string s3 = strs2.SingleOrDefault(); //获取集合中的唯一一个元素,如果没有元素则返回null,
//如果有多个元素,则抛异常
Console.WriteLine("====================================");
List<int> list2 = new List<int>() { 3, 9, 8, 90, 10, 35 };
foreach (var item in list2.Where(i => i > 7).OrderBy(i => i).Select(i => i + 10))
{
Console.WriteLine(item);
}
int max = list2.Where(i => i > 7).Max();
Console.WriteLine(max);
Console.ReadLine();
}
}
class Person
{
public Person()
{
}
public Person(string name, int age)
{
Name = name;
Age = age;
}
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
{
return "Name = " + Name + ", Age = " + Age;
}
}
public static class MyEx
{
public static int MySum<T>(this IEnumerable<T> data, Func<T, int> func)
{
int sum = 0;
foreach (var item in data)
{
sum += func(item);
}
return sum;
}
}
}
委托对象可以“+相加”,调用组合后的新委托对象会依次调用被组合起来的委托:MyDel m5 = m1+m2+m3;
组合的委托必须是同一个委托类型。
委托的“-”则是从组合委托中把委托移除;
委托如果有返回值,则有一些特殊。委托的组合一般是给事件用的,用普通的委托的时候很少用。
namespace NS
{
delegate void MyDel(int i);
internal class Program
{
static void Main(string[] args)
{
MyDel d1 = F1; //MyDel d1 = new MyDel(F1);
MyDel d2 = F2;
MyDel d3 = F3;
MyDel d4 = d1 + d2 + d3;
MyDel d5 = new MyDel(F1) + new MyDel(F2) + new MyDel(F3);
d4(10);
d4 = d4 - d2;
Console.WriteLine("第二次调用d4");
d4(20);
Console.ReadLine();
}
static void F1(int i)
{
Console.WriteLine("我是f1:" + i);
}
static void F2(int i)
{
Console.WriteLine("我是f2:" + i);
}
static void F3(int i)
{
Console.WriteLine("我是f3:" + i);
}
}
}
案例:定义一个Person类,定义一个监听年龄变化的事件,当本命年的时候祝贺一下。触发事件的地方要判断一下是不是事件null。
事件语法:event Mydelegate mdl;
加了event关键字实现事件机制的好处:用了event事件,不可以修改事件已经注册的值;不可以冒充进行事件通知了。只能+=、-=!
namespace NS
{
internal class Program
{
static void Main(string[] args)
{
Person p1 = new Person();
p1.OnBenMingNian += BMN; //方法的参数返回值要和事件的委托一致\
p1.OnBenMingNian += BMN2;
p1.OnBenMingNian = null;
p1.Age = 5;
Console.WriteLine(p1.Age);
p1.Age = 24;
Console.WriteLine(p1.Age);
Console.ReadLine();
}
static void BMN()
{
Console.WriteLine("BMN()到了本命年了!");
}
static void BMN2()
{
Console.WriteLine("BMN2()到了本命年了!");
}
}
class Person
{
private int _Age;
public int Age
{
get { return _Age; }
set
{
_Age = value;
if (_Age % 12 == 0)
{
if (OnBenMingNian != null)
{
OnBenMingNian();
}
}
}
}
//public event Action OnBenMingNian; //event 委托类型事件的名字;
public Action OnBenMingNian; //event 委托类型事件的名字;
}
}
委托的作用:占位,在不知道将来要执行的方法的具体代码时,可以先用一个委托变量来代替方法调用(委托的返回值,参数列表要确定)。在实际调用之前,需要为委托赋值,否则为null。
事件的作用:事件的作用与委托变量一样,只是功能上比委托变量有更多的限制。(比如:1.只能通过+=或-=来绑定方法(事件处理程序)2.只能在类内部调用(触发)事件。)
(面试题)事件和委托的关系:事件由一个私有的委托变量和add_***和remove_***方法组成;
事件的非简化写法:声明一个私有的委托变量和add、remove方法。
委托和事件的区别和关系
一种错误的说法“事件是一种特殊的委托”,事件是由一个私有委托和add、remove两个方法组成的。
委托用的比较多,事件只有开发WinForm、WPF的时候用的才比较多。
事件、索引器、属性本质上都是方法。
(面试题)接口中可以定义什么?
答:接口中只可以定义方法。接口中也可以定义“事件、索引器、属性”,因为他们本质上也都是方法。
namespace NS
{
internal class Program
{
static void Main(string[] args)
{
Person p1 = new Person();
p1.OnBenMingNian += BMN; //方法的参数返回值要和事件的委托一致\
p1.OnBenMingNian += BMN2;
//p1.OnBenMingNian = null;
p1.Age = 5;
Console.WriteLine(p1.Age);
p1.Age = 24;
Console.WriteLine(p1.Age);
Console.ReadLine();
}
static void BMN()
{
Console.WriteLine("BMN()到了本命年了!");
}
static void BMN2()
{
Console.WriteLine("BMN2()到了本命年了!");
}
}
class Person
{
private int _Age;
public int Age
{
get { return _Age; }
set
{
_Age = value;
if (_Age % 12 == 0)
{
//if (OnBenMingNian != null)
//{
// OnBenMingNian();
//}
if (_OnBenMingNian != null)
{
_OnBenMingNian();
}
}
}
}
//public event Action OnBenMingNian; //event 委托类型事件的名字;
//public Action OnBenMingNian; //加上event就是事件,不加event就是委托;
//事件是由私有的委托+add+remove组成
private Action _OnBenMingNian;
public event Action OnBenMingNian
{
add
{
this._OnBenMingNian += value;
}
remove
{
this._OnBenMingNian -= value;
}
}
}
}