- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
大家好!我是付工.
十年前,刚开始学C#编程的时候,被委托困扰了很久.
今天跟大家分享一下关于委托的那些事儿.
什么是委托?
抛开编程,委托是一个汉语词语,指的是把事情托付给别人或别的机构办理.
为什么会有委托?什么时候使用委托?
有些事情我们直接干不了,需要找人来帮忙.
比如:
我们需要在主窗体中刷新子窗体的控件, 。
我们需要在多线程中刷新主线程的控件.
我们需要在某个窗体中执行另一个窗体的方法.
总之,当我们直接完成不了的时候,就可以考虑使用委托,如果可以直接完成,就没有委托什么事了.
今天,我们结合一个案例来了解委托的前世今生.
这个错误应该每个人都遇到过,代码很简单,一运行就报错.
我们来分析一下错误提示:线程间操作无效:从不是创建控件“FrmMain”线程访问它.
这里的线程间意味着涉及两个线程,一个就是我们开的线程,另一个就是主线程.
从不是创建控件“FrmMain”线程,指的是什么线程呢?
我们知道程序运行之后,就会有一个主线程,又叫UI线程,通常用于处理用户界面相关的逻辑,如创建和显示窗体、处理用户输入、更新UI等.
所以,创建控件"FrmMain"的线程就是主线程.
不是创建控件“FrmMain”线程指的就是我们开的那个线程.
因此这个错误的意思就是不能在多线程里直接访问主线程的控件.
这个我们做牛马的应该都能理解,比如你花了半个月写了一个很牛的程序,你的同事想要"窃取",你是否愿意?
主线程辛辛苦苦创建了控件,多线程想直接给它赋值,主线程自然也不愿意,一怒之下,就给出了一个错误警告.
我们回到这个问题上:你花了半个月写了一个很牛的程序,你的同事想要"窃取",你不愿意给,他怎么办呢?
于是,聪明的他开始搬救兵,找到了你的领导,表示他有一个类似的项目,利润很高,客户很急,需要借用你的程序参考一下.
于是,你的领导跟你画了一张饼,毋庸置疑,你同意了.
你的同事就是那个线程,而你就是主线程,你的领导就是委托.
我们再回到这个错误上来,既然直接不能访问主线程的控件,那么就采用"委托"来实现.
想要使用委托,必然要先学会委托.
在C#中,委托是一种类型,它定义了方法的签名,即方法的参数类型和返回值类型.
这句话如果没看明白,就不用管它了.
我们先来看看如何使用委托,这里总结了委托的五步法:
1、声明委托 。
声明委托需要根据最终执行方法来确定参数与返回值类型,然后根据参数和返回值来声明.
我们目的是给lbl_Time控件赋值当前时间,因此参数和返回值均为空.
声明委托代码如下 。
//【1】声明委托 public delegate void SetTimeDelegate();
2、创建委托对象 。
委托是一种类型,就像类class一样,我们都知道如果要创建某个类的对象的写法,那么创建委托对象是一样的.
创建委托对象代码如下:
//【2】创建委托对象 private SetTimeDelegate setTime;
3、创建委托方法 。
委托对象就像领导一样,它是不干活的,最终干活的还得是下面的牛马.
因此我们需要编写一个最终干活的方法,我们这个活很简单,所以委托方法也很简单.
创建委托方法代码如下:
//【3】创建委托方法 private void setTimeMethod() { this.lbl_Time.Text = DateTime.Now.ToString("HH:mm:ss"); }
4、委托绑定 。
领导有了,牛马有了,如何将这两者联系起来呢?
我们需要进行关系绑定,这就需要进行委托绑定.
委托绑定代码如下:
//【4】委托绑定 this.setTime = this.setTimeMethod;
5、委托调用 。
如果不涉及多线程,直接就像调用方法一样调用委托对象即可.
但是这里涉及到了多线程,也就是我们这里最终仍然需要主线程来调用.
怎么通过主线程来调用这个委托对象呢?
Control类中提供了一个Invoke方法,这个方法的含义是在拥有此控件的基础窗体句柄的线程上执行指定的委托.
委托调用的代码如下:
//多线程方法
private void TaskMethod()
{
//【5】调用委托
this.lbl_Time.Invoke(setTime);
}
这样就基于委托解决了跨线程访问的问题.
我们运行一下程序,效果如下:
这时候,我们在看这句话,是不是就豁然开朗了呢?
委托是一种类型,它定义了方法的签名,即方法的参数类型和返回值类型.
如果我们接触过C++编程,委托类似于C++中的指针.
.Net Framework3.5之后开始有了Action和Func,Action和Func是内置委托,也叫系统委托,就是微软的工程师帮我们在底层写好了委托声明,这样我们就不需要声明委托.
Action委托针对无返回值情况,具有Action、Action<T>、Action<T1,T2>、Action<T1,T2,T3>……Action<T1,……T16>多达16个参数的形式,其中传入参数均采用泛型T,涵盖了几乎所有可能存在的无返回值的委托类型.
Func委托针对有返回值情况,具有Func<TResult>、Func<T,Tresult>……Func<T1,T2,T3……,Tresult>17种类型重载,T1……T16为参数,Tresult为返回类型.
于是我们开始简化我们的代码:
第一步简化:使用Action,不需要声明委托,创建的时候直接绑定 。
//多线程方法 private void TaskMethod() { //创建并绑定 Action action = new Action(setTimeMethod); //调用委托 this.lbl_Time.Invoke(action); }
第二步简化:action对象只使用一次,直接调用即可 。
//多线程方法 private void TaskMethod() { //创建委托、绑定委托、调用委托 this.lbl_Time.Invoke(new Action(setTimeMethod)); }
第三步简化:使用Lambda表达式替换委托方法 。
//多线程方法 private void TaskMethod() { //创建委托、委托方法、绑定委托、调用委托 this.lbl_Time.Invoke(new Action(()=> { this.lbl_Time.Text = DateTime.Now.ToString("HH:mm:ss"); })); }
这个最终简化的代码是不是非常熟悉呢?
最后此篇关于C#委托的前世今生的文章就讲到这里了,如果你想了解更多关于C#委托的前世今生的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我有一个加载 View 的 View ,需要将 View 推送到主导航 Controller 。 我已经为每个 View 设置了一个委托(delegate),并且基本上使我的调用沿着“链”返回到主导航
我通过 NSURLConnction 从服务器获取数据,并希望从获取的数组中填充表格 View 。数据出现在 NSURLConnection 委托(delegate)方法的日志中,但我意识到 numb
我已经将我用作标题 View 的 View 子类化,它里面有一些按钮委托(delegate),它工作得很好。 但是,我在 viewController 上方展示了一个 modalViewControl
我希望这听起来像是一个显而易见的问题,但是委托(delegate)返回类型是否也必须与其委托(delegate)的方法的返回类型相匹配? EG,像这样: public static void Save
我想使用 Kotlin 委托(delegate),但我不想在委托(delegate)人之外创建委托(delegate)。委托(delegate)的所有示例都如下所示: interface Worker
我有一个问题: - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInf
伙计们。我正在寻求帮助。这似乎是一个非常简单的任务,但我可以解决一整天。我正在尝试使用容器 View 创建侧面菜单。当用户按下“更多”按钮(barButtonItem)时,整个 View 向右滑动并出
我正在努力将 UIWebView 迁移到 WKWebView。我已经更改了所有委托(delegate)方法。我需要 WKWebView 委托(delegate)方法等于下面的 UIWebView 委托
我正在学习 VB.NET 中的委托(delegate),但对委托(delegate)类型感到困惑。在阅读有关委托(delegate)的内容时,我了解到委托(delegate)是一种数据类型,可以引用具
我有一个用 Objetive-C 构建的框架。该框架用于连接蓝牙设备并与之交互。 在演示代码中,Objetive-C 委托(delegate)函数如下所示。演示代码由框架创建者提供。 -(void)b
//NewCharts.h #import @interface NewCharts : UIViewController @property(nonatomic,retain)IBOutlet U
我正在努力了解 async/await 并认为我确实了解有关用法的一些事情。但仍然不太清楚在下面的场景中实际好处是什么。 查看 Task.Run 用法。第一种方法使用普通委托(delegate)并使用
我已经尝试了在我的网站上使用 openID 委托(delegate)的所有可能选项,但没有一个方法对我有用。 我的 HTML 文件的 head 部分有“link rel”标签。 我在 HTML 文件的
如何快速创建一个委托(delegate),即 NSUserNotificationCenterDelegate? 最佳答案 这里有一些关于两个 View Controller 之间委托(delegat
我有一个带有数据源的 NSComboBox,当您单击三角形并通过单击它选择其中一个项目时,它可以完美运行。但是,我还希望它允许用户在框中键入以使用自动完成来选择名称。目前,当用户键入时,我希望选择的项
我在代码中定义了以下类和委托(delegate)(为简洁起见,剪掉了许多其他行)。 Public Delegate Sub TimerCallback(canceled As Boolean) Pub
我使用 ansible 2.1 并且我想使用 delegate_to 向一组主机运行命令。我使用 localhost 作为主机参数,并且我想将“touch”命令委托(delegate)给两个 cls
我想通过重载为我的类实现几个构造函数。据我了解,遵循 DRY 原则的惯用方式是使用一种称为委托(delegate)构造函数的功能。我也看到了关于在任何地方使用引用参数并不惜一切代价避免使用指针的想法,
代表们会导致内存泄漏吗? 我的意思是,例如如果一个类A包含一个ADelegate,并且后者指向BMethod(属于B类),这可以防止GC收集A类或B类吗? 如果是这样,我们如何“释放”代表(设置ADe
委托(delegate)命令和路由命令有什么区别? 我读了一些文章说在 MVVM 上使用委托(delegate)命令而不是路由命令。 那么当我们使用 MVVM 时,Delegate Command 相
我是一名优秀的程序员,十分优秀!