C# 委托(delegate) 详解
概念:
类似C/C++的函数指针。委托是一种引用类型变量, 存有一系列对象方法的地址,是对一系列方法的引用的一种引用类型变量。调用委托的时候,它所引用的所有方法都会被执行。
通俗来说。委托对象是用来存放某一类别的方法调用清单,这一类别要求方法签名(方法的参数,返回值)与委托类型签名一致。当这个清单被调用时,清单内的方法也会依次执行。
.NET 自带的委托
.NET提供了两个自带的委托类型。两种委托类型已经能够胜任绝大部分开发需求。它们分别是 Action<T>与Func<T,TResult> 委托。
=>T:此委托封装的方法的参数类型。
=>TResult:此委托封装的方法的返回值类型。
T与TResult都为逆变类型参数。即,可以使用指定的类型,也可以使用派生程度更低的类型。
两种委托类型的区别是什么?
对于一个没有返回值的方法,应该使用Action封装。如果一个方法带有返回值 则使用Func。
Action委托
1.简单举例:
internal class Program
{
static void Main(string[] args)
{
Boy boy = new Boy("Jack");
Action a1 = new Action(boy.Eat);
a1.Invoke();
Action<int> a2 = new Action<int>(boy.Sleep);
a2(10);
}
class Boy
{
public Boy(string name)
{
Name = name;
}
public string Name { get; set; }
public void Eat()
{
Console.WriteLine($"男孩 {Name} 正在吃东西...");
}
public void Sleep(int time)
{
Console.WriteLine($"男孩 {Name} 一共睡了 {time} 小时");
}
}
}
此例声明一个Boy类 中含有两个方法。Eat方法无参数,Sleep需要一个Int参数.且都无返回值。
如果需要使用Action包装boy的两个方法我们就需要声明与此方法相同的签名的Action对象。如上例所示 分别声明了两个签名与方法相同的Action对象。
2.对于委托对象时有几种不同的声明方式和调用方式,下面出了举例:
Action a1 = new Action(boy.Eat);//声明方式1
Action a2 = boy.Eat;//声明方式2
Action a3 = () => {//声明方式3
boy.Eat();
Console.WriteLine("Lambda表达式声明...");
a1.Invoke();//调用方式1
a2();//调用方式2
声明方式: 1.new关键字 2.直接赋值 3.Lambda表达式
3.下面是对Action对象的一些定义案例
Action委托至少0个参数,至多16个参数,无返回值。
Action 表示无参,无返回值的委托。
Action<int,string> 表示有传入参数int,string无返回值的委托。
Action<int,string,bool> 表示有传入参数int,string,bool无返回值的委托。
Action<int,int,int,int> 表示有传入4个int型参数,无返回值的委托。
Func委托
1.简单举例
static void Main(string[] args)
{
Boy boy = new Boy("Jack");
Func<int,int,int> f1 = new Func<int, int, int>(boy.DoSum);
Console.WriteLine(f1.Invoke(1,1));
Func<double, double, double> f2 = new Func<double, double, double>(boy.DoDiv);
Console.WriteLine(f2.Invoke(10,3));
}
class Boy
{
public Boy(string name)
{
Name = name;
}
public string Name { get; set; }
public int DoSum(int x,int y)
{
return x + y;
}
public double DoDiv(double x, double y)
{
return x / y;
}
}
上例中定义了两个方法,方法分别有着不同的返回值类型。在声明func委托时应该注意签名的一致。
DoSum返回值为int,并且拥有两个int类型参数。所以使用委托类型Func<int,int,int>(此处的第一个int为TResult即返回值类型)
DoDiv返回值为double,并且拥有两个int类型参数。所以使用委托类型Func<double,int,int>(此处的第一个int为TResult即返回值类型)
自定义委托(delegate)
首先要撇清的关系
delegate和Delegate的区别
1.Delegate 是一个不折不扣的类。
2.delegate 是关键字,用来声明委托类。
3.类 Delegate 是委托类型的基类。 但是,只有系统和编译器才能从 Delegate 类或 MulticastDelegate 类显式派生。 此外,不允许从委托类型派生新类型。
声明
因为委托delegate是一种类。所以声明时请与class同级,一般情况下不需要嵌套class声明委托类。
1.委托类声明格式:
修饰符 delegate 返回值类型 委托名 ( 参数列表 );
举个栗子:
public delegate void Mydelegate();
2.声明此委托对象的格式:
委托名 委托对象名 = new 委托名 ( 方法名 );
举个栗子:
Mydelegate d1 = new Mydelegate( 方法名 );
这里需要注意方法与委托对象签名的一致性
简单示例
public delegate int Mydelegate(int a, int b);
internal class Program
{
static void Main(string[] args)
{
Boy boy = new Boy("jack");
Mydelegate dosum = new Mydelegate(boy.DoSum);
Console.WriteLine(dosum(1,5));
}
class Boy
{
public Boy(string name)
{
Name = name;
}
public string Name { get; set; }
public int DoSum(int x,int y)
{
return x + y;
}
}
}
为了与public int DoSum(int x,int y)有相同的签名。此处声明了返回值为int 同时带两个参数为int的委托类 Mydelegate
合并委托(多播)
概念
在概念中说过。委托对象是用来存放一系列方法的调用清单,这说明一个委托对象中可以同时存放多个方法。但前提是方法的签名必须与委托一致。
使用+=和-=操作符来添加/删除委托中的方法
格式:
委托对象 += 方法名
委托对象 -= 方法名
简单举例
public delegate void Mydelegate();
internal class Program
{
static void Main(string[] args)
{
Boy boy = new Boy("jack");
Mydelegate d1 =new Mydelegate(boy.DoHomeWork);
d1+= boy.Jump;
d1+= boy.Think;
d1.Invoke();
}
class Boy
{
public Boy(string name)
{
Name = name;
}
public string Name { get; set; }
public void DoHomeWork()
{
Console.WriteLine($"{Name} 正在做作业...");
}
public void Jump()
{
Console.WriteLine($"{Name} 正在跳...");
}
public void Think()
{
Console.WriteLine($"{Name} 正在思考...");
}
}
}
输出:
jack 正在做作业...
jack 正在跳...
前排提示
??前排提示:异步委托在.net core中已经被砍掉
详细相关:
https://devblogs.microsoft.com/dotnet/migrating-delegate-begininvoke-calls-for-net-core/
概念
上文中提过调用委托的方式有这样一种 => 委托对象.Invoke()
委托对象.Invoke() 是以同步委托的方式来调用此方法
此外还有另一种 =>委托对象.Begininvoke()
1.同步委托调用 Invoke()
2.异步委托调用 Begininvoke(callback,object)
同步委托上文已经提过。下文主要提提异步委托
BeginInvoke 方法启动异步调用。 该方法具有与你要异步执行的方法相同的参数,另加两个可选参数。 第一个参数是一个 AsyncCallback 委托,此委托引用在异步调用完成时要调用的方法。 第二个参数是一个用户定义的对象,该对象将信息传递到回调方法。 BeginInvoke 将立即返回,而不会等待异步调用完成。 BeginInvoke 返回可用于监视异步调用的进度的 IAsyncResult。
简单示例
internal class Program
{
static void Main(string[] args)
{
Boy boy1 = new Boy(“Jack”, ConsoleColor.DarkBlue);
Boy boy2 = new Boy(“Bob”, ConsoleColor.Red);
Boy boy3 = new Boy(“Anna”, ConsoleColor.Yellow);
Action a1 = boy1.DoHomeWork;
Action a2 = boy2.DoHomeWork;
Action a3 = boy3.DoHomeWork;
a1.BeginInvoke(boy1.FinshWork,boy1.Name);
a2.BeginInvoke(boy1.FinshWork, boy2.Name);
a3.BeginInvoke(boy1.FinshWork, boy3.Name);
}
class Boy
{
public Boy(string name, ConsoleColor penColor)
{
Name = name;
PenColor = penColor;
}
public string Name { get; set; }
public ConsoleColor PenColor { get; set; }
public void DoHomeWork()
{
for (int i = 0; i < 3; i++)
{
Console.WriteLine(Name+"正在做第 "+(i+1)+" 个作业...");
Thread.Sleep(1000);
}
}
public void FinshWork(IAsyncResult ar)
{
Console.WriteLine(ar.AsyncState +"做完了作业");
}
}
————————————————
版权声明:本文为CSDN博主「soar+」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_35652006/article/details/128928017
类似C/C++的函数指针。委托是一种引用类型变量, 存有一系列对象方法的地址,是对一系列方法的引用的一种引用类型变量。调用委托的时候,它所引用的所有方法都会被执行。
通俗来说。委托对象是用来存放某一类别的方法调用清单,这一类别要求方法签名(方法的参数,返回值)与委托类型签名一致。当这个清单被调用时,清单内的方法也会依次执行。
.NET 自带的委托
.NET提供了两个自带的委托类型。两种委托类型已经能够胜任绝大部分开发需求。它们分别是 Action<T>与Func<T,TResult> 委托。
=>T:此委托封装的方法的参数类型。
=>TResult:此委托封装的方法的返回值类型。
T与TResult都为逆变类型参数。即,可以使用指定的类型,也可以使用派生程度更低的类型。
两种委托类型的区别是什么?
对于一个没有返回值的方法,应该使用Action封装。如果一个方法带有返回值 则使用Func。
Action委托
1.简单举例:
internal class Program
{
static void Main(string[] args)
{
Boy boy = new Boy("Jack");
Action a1 = new Action(boy.Eat);
a1.Invoke();
Action<int> a2 = new Action<int>(boy.Sleep);
a2(10);
}
class Boy
{
public Boy(string name)
{
Name = name;
}
public string Name { get; set; }
public void Eat()
{
Console.WriteLine($"男孩 {Name} 正在吃东西...");
}
public void Sleep(int time)
{
Console.WriteLine($"男孩 {Name} 一共睡了 {time} 小时");
}
}
}
此例声明一个Boy类 中含有两个方法。Eat方法无参数,Sleep需要一个Int参数.且都无返回值。
如果需要使用Action包装boy的两个方法我们就需要声明与此方法相同的签名的Action对象。如上例所示 分别声明了两个签名与方法相同的Action对象。
2.对于委托对象时有几种不同的声明方式和调用方式,下面出了举例:
Action a1 = new Action(boy.Eat);//声明方式1
Action a2 = boy.Eat;//声明方式2
Action a3 = () => {//声明方式3
boy.Eat();
Console.WriteLine("Lambda表达式声明...");
a1.Invoke();//调用方式1
a2();//调用方式2
};
声明方式: 1.new关键字 2.直接赋值 3.Lambda表达式
调用方式: 1.对象名.Invoke(参数) 2.对象名(参数)
3.下面是对Action对象的一些定义案例
Action委托至少0个参数,至多16个参数,无返回值。
Action 表示无参,无返回值的委托。
Action<int,string> 表示有传入参数int,string无返回值的委托。
Action<int,string,bool> 表示有传入参数int,string,bool无返回值的委托。
Action<int,int,int,int> 表示有传入4个int型参数,无返回值的委托。
Func委托
1.简单举例
static void Main(string[] args)
{
Boy boy = new Boy("Jack");
Func<int,int,int> f1 = new Func<int, int, int>(boy.DoSum);
Console.WriteLine(f1.Invoke(1,1));
Func<double, double, double> f2 = new Func<double, double, double>(boy.DoDiv);
Console.WriteLine(f2.Invoke(10,3));
}
class Boy
{
public Boy(string name)
{
Name = name;
}
public string Name { get; set; }
public int DoSum(int x,int y)
{
return x + y;
}
public double DoDiv(double x, double y)
{
return x / y;
}
}
上例中定义了两个方法,方法分别有着不同的返回值类型。在声明func委托时应该注意签名的一致。
DoSum返回值为int,并且拥有两个int类型参数。所以使用委托类型Func<int,int,int>(此处的第一个int为TResult即返回值类型)
DoDiv返回值为double,并且拥有两个int类型参数。所以使用委托类型Func<double,int,int>(此处的第一个int为TResult即返回值类型)
自定义委托(delegate)
首先要撇清的关系
delegate和Delegate的区别
1.Delegate 是一个不折不扣的类。
2.delegate 是关键字,用来声明委托类。
3.类 Delegate 是委托类型的基类。 但是,只有系统和编译器才能从 Delegate 类或 MulticastDelegate 类显式派生。 此外,不允许从委托类型派生新类型。
声明
因为委托delegate是一种类。所以声明时请与class同级,一般情况下不需要嵌套class声明委托类。
1.委托类声明格式:
修饰符 delegate 返回值类型 委托名 ( 参数列表 );
举个栗子:
public delegate void Mydelegate();
2.声明此委托对象的格式:
委托名 委托对象名 = new 委托名 ( 方法名 );
举个栗子:
Mydelegate d1 = new Mydelegate( 方法名 );
这里需要注意方法与委托对象签名的一致性
简单示例
public delegate int Mydelegate(int a, int b);
internal class Program
{
static void Main(string[] args)
{
Boy boy = new Boy("jack");
Mydelegate dosum = new Mydelegate(boy.DoSum);
Console.WriteLine(dosum(1,5));
}
class Boy
{
public Boy(string name)
{
Name = name;
}
public string Name { get; set; }
public int DoSum(int x,int y)
{
return x + y;
}
}
}
为了与public int DoSum(int x,int y)有相同的签名。此处声明了返回值为int 同时带两个参数为int的委托类 Mydelegate
合并委托(多播)
概念
在概念中说过。委托对象是用来存放一系列方法的调用清单,这说明一个委托对象中可以同时存放多个方法。但前提是方法的签名必须与委托一致。
使用+=和-=操作符来添加/删除委托中的方法
格式:
委托对象 += 方法名
委托对象 -= 方法名
简单举例
public delegate void Mydelegate();
internal class Program
{
static void Main(string[] args)
{
Boy boy = new Boy("jack");
Mydelegate d1 =new Mydelegate(boy.DoHomeWork);
d1+= boy.Jump;
d1+= boy.Think;
d1.Invoke();
}
class Boy
{
public Boy(string name)
{
Name = name;
}
public string Name { get; set; }
public void DoHomeWork()
{
Console.WriteLine($"{Name} 正在做作业...");
}
public void Jump()
{
Console.WriteLine($"{Name} 正在跳...");
}
public void Think()
{
Console.WriteLine($"{Name} 正在思考...");
}
}
}
输出:
jack 正在做作业...
jack 正在跳...
jack 正在思考...
异步委托与同步委托前排提示
??前排提示:异步委托在.net core中已经被砍掉
详细相关:
https://devblogs.microsoft.com/dotnet/migrating-delegate-begininvoke-calls-for-net-core/
概念
上文中提过调用委托的方式有这样一种 => 委托对象.Invoke()
委托对象.Invoke() 是以同步委托的方式来调用此方法
此外还有另一种 =>委托对象.Begininvoke()
1.同步委托调用 Invoke()
2.异步委托调用 Begininvoke(callback,object)
同步委托上文已经提过。下文主要提提异步委托
BeginInvoke 方法启动异步调用。 该方法具有与你要异步执行的方法相同的参数,另加两个可选参数。 第一个参数是一个 AsyncCallback 委托,此委托引用在异步调用完成时要调用的方法。 第二个参数是一个用户定义的对象,该对象将信息传递到回调方法。 BeginInvoke 将立即返回,而不会等待异步调用完成。 BeginInvoke 返回可用于监视异步调用的进度的 IAsyncResult。
简单示例
internal class Program
{
static void Main(string[] args)
{
Boy boy1 = new Boy(“Jack”, ConsoleColor.DarkBlue);
Boy boy2 = new Boy(“Bob”, ConsoleColor.Red);
Boy boy3 = new Boy(“Anna”, ConsoleColor.Yellow);
Action a1 = boy1.DoHomeWork;
Action a2 = boy2.DoHomeWork;
Action a3 = boy3.DoHomeWork;
a1.BeginInvoke(boy1.FinshWork,boy1.Name);
a2.BeginInvoke(boy1.FinshWork, boy2.Name);
a3.BeginInvoke(boy1.FinshWork, boy3.Name);
}
class Boy
{
public Boy(string name, ConsoleColor penColor)
{
Name = name;
PenColor = penColor;
}
public string Name { get; set; }
public ConsoleColor PenColor { get; set; }
public void DoHomeWork()
{
for (int i = 0; i < 3; i++)
{
Console.WriteLine(Name+"正在做第 "+(i+1)+" 个作业...");
Thread.Sleep(1000);
}
}
public void FinshWork(IAsyncResult ar)
{
Console.WriteLine(ar.AsyncState +"做完了作业");
}
}
————————————————
版权声明:本文为CSDN博主「soar+」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_35652006/article/details/128928017
本站大部分文章、数据、图片均来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了您的权益请来信告知我们删除。邮箱:1451803763@qq.com