title author date CreateTime categories
C#委托
lindexi
2019-09-02 12:57:37 +0800
2018-2-13 17:23:3 +0800
C#

关于什么是委托,委托如何使用,我在这里就不说了。
需要说的:

  1. 委托是函数指针链
  2. 委托的 BeginInvoke
  3. 委托如果出现异常,会如何

如果不知道函数指针,可以继续往下看,我来告诉大家,为何需要委托。

假如在写游戏,有一个人物,他会升级,那么在他升级的时候,需要给他添加潜力值,而判断升级是经验类需要写的。

先写一个经验类。

    核心
如果当前经验大于最大经验,升级。

但是升级是在经验类里,经验类外的人物不会知道已经升级了,那么如何让人物知道升级?

这时可以使用委托。

     如果当前经验大于最大经验
调用函数升级

那么函数 升级 如何让人物知道,可以使用一个委托

    升级
调用委托

于是人物可以添加函数到经验。

    经验.升级=人物.升级

这样,经验的升级就是使用人物的升级,可以使用其他类的函数。

上面没有代码,现在来说个有代码的。

假如需要去寄快递,那么需要找邮递,把东西给他

假设有个邮递,可以寄快递

    class 邮递
{ public static Action 寄快递;
}

委托最好用Action

这里定义委托是,不知道会是哪个快递员会去寄快递,在实际,谁也不知道最后是哪个,快递员可能说不想干了,实际快递太辛苦,大家多体谅。所以不能写函数说,快递A 给 小明去寄,因为不知道小明是不是今天上班。

来写一个 主角 张 ,他需要去寄快递。

    class MrZhang
{
public void 寄快递()
{
邮递.寄快递();
} }

不知道是谁上班,但是我可以寄快递。

最后,今天来上班的快递员

    快递员 a = new 快递员();
邮递.寄快递 = a.寄快递; class 快递员
{ public void 寄快递()
{ }
}

就是快递,所以这就是委托使用。

使用一个函数,不知道他是谁用的,可以使用委托。

如果使用的委托是 多播,那么小心用 BeginInvoke

如果使用 同步,那么多个方法是可以运行

            static void Main(string[] args)
{
Action m = M1;
m += M2;
m.Invoke();
} private static void M1()
{
p();
} private static void M2()
{
p();
} private static void p()
{
Console.WriteLine("线程ID为:{0}", Thread.CurrentThread.ManagedThreadId);
}

如果使用的BeginInvoke,那么在委托多播使用 BeginInvoke 会报异常 System.ArgumentException:“The delegate must have only one target.”

在一个线程不能同时执行多个方法,使用 BeginInvoke 必须在多个线程,所以可以使用 获得所有方法,然后执行

        static void Main(string[] args)
{
Action m = M1;
m += M2;
//m.Invoke();
List<IAsyncResult> list=new List<IAsyncResult>();
var invtl = m.GetInvocationList().OfType<Action>().ToList();
foreach (Action temp in invtl)
{
list.Add(temp.BeginInvoke((e) => { }, null));
} for (int i = 0; i < invtl.Count(); i++)
{
invtl[i].EndInvoke(list[i]);
} } private static void M1()
{
p();
} private static void M2()
{
p();
} private static void p()
{
Console.WriteLine("线程ID为:{0}", Thread.CurrentThread.ManagedThreadId);
}

有两个需要知道:

m.GetInvocationList() 得到 Delegate 不能直接执行。

需要转类型,定义是知道他是什么类型,上面使用的是 Action ,所以可以转 Action ,如果是自定义的,那么使用自定义的。

第二,如果使用 BeginInvoke ,在等待时,需要拿到 IAsyncResult 才可以。

    var temp = m.BeginInvoke((e) => { }, null);
m.EndInvoke(temp);

上面代码:如果要使用 BeginInvoke ,小心 Delegate 是多个函数,不是一个函数,所以使用时,建议使用

            var invtl = m.GetInvocationList().OfType<Action>().ToList();
foreach (Action temp in invtl)
{
list.Add(temp.BeginInvoke((e) => { }, null));
}

需要把类型换自己的类型。

如果委托发生异常

如果委托方法里没有 try catch,那么如果使用 invoke, 委托是函数指针链,所以会在执行异常退出。

如果使用 BeginInvoke ,那么会在 EndInvoke 退出。

        static void Main(string[] args)
{
Action m = M1;
m += M2;
//m.Invoke();
List<IAsyncResult> list=new List<IAsyncResult>();
var invtl = m.GetInvocationList().OfType<Action>().ToList();
foreach (Action temp in invtl)
{
list.Add(temp.BeginInvoke((e) => { }, null));
} //for (int i = 0; i < invtl.Count(); i++)
//{
// invtl[i].EndInvoke(list[i]);
//} } private static void M1()
{
p();
throw new ArgumentException();
} private static void M2()
{
p();
throw new ArgumentException();
} private static void p()
{
Console.WriteLine("线程ID为:{0}", Thread.CurrentThread.ManagedThreadId);
}

上面代码没有 EndInvoke 不会有异常,异常发生在别线程,所以不会在Main函数异常。

如果使用 EndInvoke 会在 Main 异常

           static void Main(string[] args)
{
Action m = M1;
m += M2;
//m.Invoke();
List<IAsyncResult> list=new List<IAsyncResult>();
var invtl = m.GetInvocationList().OfType<Action>().ToList();
foreach (Action temp in invtl)
{
list.Add(temp.BeginInvoke((e) => { }, null));
} for (int i = 0; i < invtl.Count(); i++)
{
invtl[i].EndInvoke(list[i]);
} } private static void M1()
{
p();
throw new ArgumentException();
} private static void M2()
{
p();
throw new ArgumentException();
} private static void p()
{
Console.WriteLine("线程ID为:{0}", Thread.CurrentThread.ManagedThreadId);
}

事件

如果事件使用 BeginInvoke 和 委托一样

            _event += (s, e) => M1();
_event += (s, e) => M2();
_event?.BeginInvoke(null, null, (e) => { }, null); private static EventHandler _event;

异常:System.ArgumentException:“The delegate must have only one target.”

需要和 委托 一样,获得函数指针,执行,如果方法里有异常,那么不会在 Main 方法异常,如果没有使用 End 。

            foreach (var temp in _event.GetInvocationList().OfType<EventHandler>())
{
temp.BeginInvoke(null, null, (e) => { }, null);
}

本文还没写好,如果有问题,请联系我

本文内容属于大量抄袭,代码是自己写,但是抄了代码大神写的,于是羞愧放下他的博客:

http://www.cnblogs.com/free722/archive/2011/04/04/2005275.html

http://stackoverflow.com/questions/25979264/understanding-the-wpf-dispatcher-begininvoke

最新文章

  1. Fedora 23 忘记root密码
  2. 微信支付 总提示get_brand_wcpay_request:fail 也不跳转支付页面 的解决方案
  3. 解决thinkPHP构造函数__construct导致tp方法冲突问题
  4. http://www.cnbeta.com/articles/306769.htm
  5. 【Weblogic】--Weblogic的部署方式和缓存
  6. js 重载i
  7. AMQ学习笔记 - 01. 相关背景
  8. Entity Framework 6.1-Model First
  9. 封装一个ISortable接口
  10. Spark运行问题备忘一(网络搜集)
  11. 【转】生产环境MySQL Server核心参数的配置
  12. IOC容器在框架中的应用
  13. 百度UEditor图片上传或文件上传路径自定义
  14. 关于Debug和Release之本质区别的讨论
  15. python笔记--2--字符串、正则表达式
  16. Dubbo中Directory解析
  17. 【备忘】SQL语句增加字段、修改字段、修改类型、修改默认值
  18. 11-(基础入门篇)WiFi模块开发,下载运行第一个程序
  19. leetcode python 001
  20. linux 的常用命令---------第十阶段

热门文章

  1. 数组归一 reduce (数组归一) reduceRight(从右至左)
  2. 一、Json
  3. Chocolatey Window系统下的软件管理工具
  4. mysql limit 数据重复及遗漏
  5. Servlet中如何获取用户提交的查询参数或表单数据?
  6. @InitBinder 前端传递date时间类型属性时,转换错误问题
  7. 几种RAID级别的比较
  8. error: Error trying to parse settings: Unexpected trailing characters in Packages\User\Preferences.sublime-settings:9:2 reloading settings Packages/User/Preferences.sublime-settings
  9. SpringMvc获取前端的数据@RequestBody请求体/@PathVaribale/@RequestParam【支持Ajax】
  10. java--substring内存溢出问题