了解知识:
委托可理解成 升级版的指针
一切都是从地址开始:
变量:以某个地址为起点的一段内存中所存储的值
函数:以某个地址为起点的一段内存中所存储的一组指令
直接调用:通过函数名来调用函数,通过函数名直接获得函数所在地址并开始执行
间接调用:通过(函数指针)来调用函数,通过读取(函数指针)里的值获得函数所在的地址并开始
执行
一、系统自带委托
1.定义一个类,创建函数
//定义一个类,创建函数
class AddPoint
{
public int Add(int a,int b){
return a+b;
}
public void ActMethod(){
Console.WriteLine("这是一个Action方法");
}
}
2.使用系统自带的委托(Func委托、Action委托)
//先实例化AddPoint类
AddPoint ap = new AddPint();
//委托也是一种类,也需要实例化,但是对标是函数方法
Action action = new Action(ap.ActMethod);
//调用Action委托的函数
action.Invoke();
//也可以写成
action();
//Func委托实例化,对标函数方法
Func<int,int,int> func = new Func<int,int,int>(ap.Add);
//调用Func委托的函数,因为Func是有返回值的(最后一个),所以用一个变量取返回值
int num = func(12,13);
//输出
Console.WriteLine(num);
//控制台停留
Console.ReadLine();
实例代码,可以直接跑
using System;
namespace weituo
{
class Program
{
static void Main(string[] args)
{
AddPoint ap = new AddPoint();
Action action = new Action(ap.ActMethod);
action();
action.Invoke();
Func<int, int, int> func = new Func<int, int, int> (ap.Add);
int b = func(2, 3);
Console.WriteLine(b);
Console.WriteLine(func(20,30));
Console.ReadLine();
}
class AddPoint {
public int Add(int a, int b)
{
int z = a + b;
return z;
}
public void ActMethod() {
Console.WriteLine("Action方法");
}
}
}
}
结果:
二、自定义委托
1.声明自定义委托
//委托声明 返回值数据类型 自定义委托名 (需要委托的函数输入)
//比大小
public delegate double BigEquip (float a ,float b);
//是否相等
public delegate bool CompareEquip (int a ,double b);
2.类中定义两个方法
//AddPoint类中定义两个方法
public double BE(float a,float b)
{
double an;
if (a > b)
{ an = a; }
else
{ an = b; }
return an;
}
public bool CE(int a,double b)
{
return a==b;
}
3.在实现类中调用
//在实现类中进行调用
static void Main(string[] args)
{
//类实例化
AddPoint ap = new AddPoint();
//委托实例化,并绑定对应的函数方法
BigEquip be = new BigEquip(ap.BE);
CompareEquip ce = new CompareEquip(ap.CE);
//输出
Console.WriteLine(be(2f,3f));
Console.WriteLine(ce(2,3));
}
实例代码,可以直接跑
using System;
namespace weituo
{
class Program
{
//比大小
public delegate double BigEquip(float a, float b);
//是否相等
public delegate bool CompareEquip(int a, double b);
static void Main(string[] args)
{
//类实例化
AddPoint ap = new AddPoint();
//委托实例化,并绑定对应的函数方法
BigEquip be = new BigEquip(ap.BE);
CompareEquip ce = new CompareEquip(ap.CE);
//输出
Console.WriteLine(be(2f, 3f));
Console.WriteLine(ce(2, 3));
Console.ReadLine();
}
class AddPoint {
public double BE(float a, float b)
{
double an;
if (a > b)
{ an = a; }
else
{ an = b; }
return an;
}
public bool CE(int a, double b)
{
return a == b;
}
}
}
}
结果:
三、实际作用:委托链
//创建一个委托
public delegate void MyDelegate();
static void Main()
{
//委托实例化并传值
MyDelegate myDelegate1 = Method1;
MyDelegate myDelegate2 = Method2;
// 创建委托链
MyDelegate myDelegateChain = myDelegate1 + myDelegate2;
// 调用委托链中的方法
myDelegateChain();
// 从委托链中移除委托实例
myDelegateChain -= myDelegate2;
// 再次调用委托链中的方法
myDelegateChain();
}
static void Method1()
{
Console.WriteLine("Method 1");
}
static void Method2()
{
Console.WriteLine("Method 2");
}
————————————————
版权声明:本文为CSDN博主「喵叔哟」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/gangzhucoll/article/details/131750446
四、实际作用:回调函数
1.先自定义一个委托
public delegate void ID(string basic);
2.创建一个与委托想匹配的方法
static void method1(string basic)
{
Console.WriteLine("当前状态:" + basic);
}
3.定义一个类,类中定义一个方法调用这个委托并实例化
class ZhuTi
{
//方法是实例化委托
public void method2(ID id)
{
Console.WriteLine("启动状态");
Thread.Sleep(2000);
Console.WriteLine("运行状态");
Thread.Sleep(2000);
id("重新开始");
}
}
4.实例化类,实现类中的方法(给委托与方法实现连接)
static void Main()
{
ZhuTi zhuti = new ZhuTi();
zhuti.method2(method1);
}
即(方便自我理解,不一定对)
一共三个类
1.创建委托(1类)
2.与委托相匹配的方法(方法1) (2类)
3.定义另一个方法2(此时将委托先实例化)(3类)
4.调用方法2的时候将方法1写入(2类)
因为创建委托,必做的两步就是实例化和传值
而与此同时,委托必须要有匹配的方法(值),因此就有以上的顺序步骤
可以跑的程序奉上
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace weituo
{
public delegate void ID(string basic);
class ZhuTi
{
public void method2(ID id)
{
Console.WriteLine("启动状态");
Thread.Sleep(2000);
Console.WriteLine("运行状态");
Thread.Sleep(2000);
id("重新开始");
}
}
class Class1
{
static void Main()
{
ZhuTi zhuti = new ZhuTi();
zhuti.method2(method1);
}
static void method1(string basic)
{
Console.WriteLine("当前状态:" + basic);
}
}
}
五、实际作用:我也没有感受到
将不同的产品装入盒子中(普通的方式写这段代码)
//可直接跑
using System;
namespace QianTao
{
class text
{
static void Main(string[] args)
{
//最简单的先将全部类实例化
Product product1 = new Product();
Box box1 = new Box();
WrapFactory wrapFactory = new WrapFactory();
ProductFactory productFactory = new ProductFactory();
//套娃开始,将一个个东西装入
//先把产品确定好
product1 = productFactory.ToyCar();
//将产品装入盒子中
box1 = wrapFactory.install(product1);
//输出
Console.WriteLine("box1装的是: " + box1.Product.Name);
//另一种写法
Box box2 = wrapFactory.install(productFactory.ToyDoll());
Console.WriteLine("box2装的是: " + box2.Product.Name);
}
}
//产品
class Product
{
//产品里的内容是产品名
public string Name { get; set; }
}
//盒子(用来装产品的)
class Box
{
//盒子里的内容是产品
public Product Product { get; set; }
}
//将产品打包到盒子中
class WrapFactory
{
//所以输入是产品,返回的是盒子
public Box install(Product product)
{
//实例化Box
Box box = new Box();
//将产品装入盒子
box.Product = product;
return box;
}
}
//生产各种各样的产品
class ProductFactory
{
public Product ToyCar()
{
//实例化产品
Product product = new Product();
//赋值给产品
product.Name = "玩具车";
return product;
}
public Product ToyDoll()
{
//同上
Product product = new Product();
product.Name = "玩偶";
return product;
}
}
}
用委托的方式写:
//可直接跑
using System;
namespace QianTao
{
class text
{
static void Main(string[] args)
{
//日常实例化
ProductFactory productFactory = new ProductFactory();
WrapFactory wrapFactory = new WrapFactory();
//调用委托的第一种写法
Func<Product> func1 = new Func<Product> ( productFactory.ToyCar );
Box box1 = new Box();
box1 = wrapFactory.install(func1);
Console.WriteLine("box1装的是:" + box1.Product.Name);
//节省写法;
Func<Product> func2 = productFactory.ToyDoll; //不知道会不会不够严谨
Box box2 = wrapFactory.install(func2);
Console.WriteLine("box2装的是:" + box2.Product.Name);
}
}
//产品
class Product
{
//产品里的内容是产品名
public string Name { get; set; }
}
//盒子(用来装产品的)
class Box
{
//盒子里的内容是产品
public Product Product { get; set; }
}
//将产品打包到盒子中
class WrapFactory
{
//所以输入是产品,返回的是盒子
//这里将产品替换成委托,但是委托的返回值依旧是产品
public Box install(Func<Product> func)
{
Box box = new Box();
box.Product = func();
return box;
}
}
//生产各种各样的产品
class ProductFactory
{
public Product ToyCar()
{
Product product = new Product();
product.Name = "玩具车";
return product;
}
public Product ToyDoll()
{
Product product = new Product();
product.Name = "玩偶";
return product;
}
}
}
以上三种实际作用,在我看来就是取代一个方法,相当于用一个变量去取代一个方法,等需要用这个方法的时候,就调用这个变量。
六、高级实际作用:多播委托
一个委托里包含多个方法,从我们一开始接触委托,其实看到的委托一直是一个委托对标一个方法,现在多播委托是,一个委托对标多个方法,当然方法肯定要同一类型。
多播委托是按照顺序连续调用方法,因此,不可能有返回值,所以返回值位void,否则就只能得委托中最后一个方法的结果
using System;
using static Program.text;
namespace Program
{
class Program
{
static void Main(string[] args)
{
//将委托实例化,并将方法对标Poet
DuoBo duobos = Poet;
//将方法Fencer传入委托中
duobos += Fencer;
//定义一个string类型
string name = "李白";
Console.WriteLine("第一种展示方式");
//将实例化的委托种的输入赋值为name
duobos(name);
Console.WriteLine("第二种展示方式");
//返回委托的调用列表,这里的delegates列表中存储的是Duobo类型的委托
Delegate[] delegates = duobos.GetInvocationList();
//foreach遍历
foreach (DuoBo duobo in delegates)
{
duobo(name);
}
}
}
class text
{
//自定义一个委托,不需要返回值,输入有一个,类型为string
public delegate void DuoBo(string name);
//定义一个名为Poet方法,不需要返回值,输入有一个,类型为string
public static void Poet(string name)
{
Console.WriteLine("诗仙:" + name);
}
//定义一个名为Fencer方法,不需要返回值,输入有一个,类型为string
public static void Fencer(string name)
{
Console.WriteLine("剑仙: " + name);
}
}
}
emmmmm,上面有些程序的结果忘记截图,问题不大
上文总结下来的多播委托,其实就是 委托 = 方法1,接着就是 委托 += 方法2,可以理解成,不断将后续方法塞进第一个方法,最后就是使用委托,委托(); 因此调用第一个方法就把所有方法按照顺序实现出来。
七、高级实际作用:隐式异步调用(使用的委托BeginInvoke)
在使用委托隐式异步调用的时候遇到这个问题。
原因是因为我创建的是.NET Core项目,但是在.NET Core中不支持Action.BeginInvoke(null, null)的委托异步调用方法。
目前的解决办法是重新创建一个.NET Framework项目(测试用的是4.5.2),把代码重新复制过去后,就没有异常了。
———————————————— 版权声明:本文为CSDN博主「爱吃柚子的梨」的原创文章,遵循CC 4.0
BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42545675/article/details/104071939
最近学习委托及异步调用碰到了这个报错Unhandled exception.
System.PlatformNotSupportedException: Operation is not supported on this platform.
at System.Action.BeginInvoke(AsyncCallback callback, Object object),很头疼,.net和.net core平台都有这个问题。
一查原来是更新后推荐使用(TAP)新的异步编程来实现,原来的BeginInvoke()不再支持了,亲测以下两篇文章都有帮助,谨此记录下。
Migrating Delegate.BeginInvoke Calls for .NET Core
System.PlatformNotSupportedException:“Operation is not supported on this platform.”
————————————————
版权声明:本文为CSDN博主「dark9spring」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/dark9spring/article/details/117922155
因为我用的版本是.NET 5.0 ,所以就不打算去专门测试了,感兴趣的可以自己试一下,用下面这个取代一下效果
七、高级实际作用:隐式异步调用(使用的Thread)
using System;
using System.Threading;
namespace YiBu
{
class Program
{
static void Main(string[] args)
{
Student st1 = new Student() { ID = 1, Pencolor = ConsoleColor.Red };
Student st2 = new Student() { ID = 2, Pencolor = ConsoleColor.Yellow };
Thread th1 = new Thread(st1.DrawColor);
Thread th2 = new Thread(st2.DrawColor);
//ac1.Invoke();
//ac2.Invoke();
th1.Start();
th2.Start();
for(int a = 0; a < 5; a++)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Student{0} Draw Color", a);
Thread.Sleep(800);
}
}
}
class Student
{
public int ID { get; set; }
public ConsoleColor Pencolor {get; set;}
public void DrawColor()
{
for (int i = 0; i < 5; i++)
{
Console.ForegroundColor = Pencolor;
Console.WriteLine("Student{0} Draw Color {1} hours", ID, i);
Thread.Sleep(1000);
}
}
}
}
输出结果(互相占用抢资源导致这种情况)
正常情况应该如下