在写delegate的时候遇到一个问题,在已有一个不带参数的delegate基础上,试图再增加一个带参数的delegate,结果VS报了“already contains a definition for ‘InvokeDelegate’”这样的错误。

第一眼看上去,代码似乎没什么问题:

 private delegate void InvokeDelegate();
private delegate void InvokeDelegate(string param);

其实这是把delegate等同于了method,所以才会认为使用method的重载方式也可以重载delegate。

翻过《CLR via C#》这本书,或者直接用ILDASM工具查看就会明白,delegate在编译时会被编译器翻译成一个继承MulticastDelegate的类。

因此,delegate真实的代码应该是这样的:

 private sealed class InvokeDelegate : MulticastDelegate
{
public InvokeDelegate(Object object, IntPtr method);
public virtual void Invoke();
public IAsyncResult BeginInvoke(AsyncCallback callback, Object object);
public virtual void EndInvoke(IAsyncResult result);
} private sealed class InvokeDelegate : MulticastDelegate
{
public InvokeDelegate(Object object, IntPtr method);
public virtual void Invoke();
public IAsyncResult BeginInvoke(string param, AsyncCallback callback, Object object);
public virtual void EndInvoke(IAsyncResult result);
}

这样就不难看出,之前的写法会生成同样名称的两个类,这个当然是不被允许的。而两者唯一的区别就在于BeginInvoke方法中的参数。

那么是否就没有办法重载delegate了呢?

再看看.NET Framework中已有的Action委托。Action,Action,Action……各种形式都有。看一下它们的语法。

Action委托:public delegate void Action()
Action委托:public delegate void Action(T obj)
Action委托:public delegate void Action(T1 arg1, T2 arg2)

显然使用泛型的方式可以实现重载delegate的需求。

如果把“private delegate void InvokeDelegate(string param);”改成“private delegate void InvokeDelegate<in T>(T param);”,会生成以下的新类。

 private sealed class InvokeDelegate<T> : MulticastDelegate
{
public InvokeDelegate(Object object, IntPtr method);
public virtual void Invoke(T param);
public IAsyncResult BeginInvoke(T param, AsyncCallback callback, Object object);
public virtual void EndInvoke(IAsyncResult result);
}

这种写法便不会与第一个delegate发生冲突了。

不过最后需要补充的是,重载delegate这样的说法并不正确,其实只是定义了不同类型的delegate,而非发生了重载操作。

原文同步发布于我的个人博客

如何重载delegate的更多相关文章

  1. Unity[C#] Reflection Use

      Reflection Reflection是C#程序员的一个最有力工具 最常用的例子来说明反射的用处是一个插件系统.假设你正在创建一个 接受用户创建 的扩展程序,有没有办法预先知道哪些方法这个扩展 ...

  2. 窥探Swift之协议(Protocol)和委托代理(Delegate)回调的使用

    协议与委托代理回调在之前的博客中也是经常提到和用到的在<Objective-C中的委托(代理)模式>和<iOS开发之窥探UICollectionViewController(四) - ...

  3. UIScrollView的delegate方法妙用之让UICollectionView滑动到某个你想要的位置

    一个UICollectionView有好多个cell,滑动一下,谁也不知道会停留在哪个cell,滑的快一点,就会多滑一段距离,反之则会滑的比较近,这正是UIScrollview用户体验好的地方. 如果 ...

  4. 01-C#入门(函数重载、委托)

    函数的重载 相对委托,是比较好理解的. 涉及一个概念:函数签名.函数签名包括函数的名称和参数,而函数重载:就是使用相同的名称和不同的参数(参数类型.传递方式[传值或引用])来实现的.而不能声明相同的函 ...

  5. C#一元运算重载的深入理解

    using System; using System.Diagnostics; using System.Text; using System.Collections; using System.Co ...

  6. C#的委托和事件(delegate)

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Dele ...

  7. CLR via C#(12)-委托Delegate

    本来按照进度应该学习事件了,可总觉得应该委托在前,事件在后,才好理解. 委托是一个类,它提供了回调函数机制,而且是类型安全的.使用委托可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数 ...

  8. Android的Proxy/Delegate Application框架 (主要介绍插件化开发)

    1. 插件化的原理 是 Java ClassLoader 的原理:Java ClassLoader基础 常用的其他解决方法还包括:Google Multidex,用 H5 代替部分逻辑,删无用代码,买 ...

  9. Delegate(委托与事件)

    Delegate可以当它是一个占位符,比如你在写代码的时候并不知道你将要处理的是什么.你只需要知道你将要引入的参数类型和输出类型是什么并定义它即可.这就是书本上所传达的方法签名必须相同的意思. 系统自 ...

随机推荐

  1. Asp.Net MVC4入门指南(5):从控制器访问数据模型

    在本节中,您将创建一个新的MoviesController类,并在这个Controller类里编写代码来取得电影数据,并使用视图模板将数据展示在浏览器里. 在开始下一步前,先Build一下应用程序(生 ...

  2. 用数组取到当前栈内的ViewController 并根据下标取某个ViewController

    NSArray *navArray = self.navigationController.viewControllers; TabsViewController *tabsVC = [[TabsVi ...

  3. nginx编译模块详解

    –prefix= 指向安装目录–sbin-path 指向(执行)程序文件(nginx)–conf-path= 指向配置文件(nginx.conf)–error-log-path= 指向错误日志目录–p ...

  4. 结构化查询语言(SQL)数据类型

    简要描述一下结构化查询语言中的五种数据类型:字符型,文本型,数值型,逻辑型和日期型. 字符型 VARCHARVS CHAR VARCHAR型和CHAR型数据的这个差别是细微的,但是非常重要.他们都是用 ...

  5. Ubuntu16.04下安装.NET Core

    以下为控制台输入代码序列一.sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet ...

  6. c# json转换实例

    用户实体: public class UserModel { public long? UserId { get; set; } public string UserName { get; set; ...

  7. wpf 后台绘制圆弧

    wpf 前台绘制圆弧很简单,如:<Path x:Name="path_data" Stroke="#FFE23838" StrokeThickness=& ...

  8. selenium隔离环境安装、以及示例

    1.virtual虚拟环境---分割项目---类似于创建文件夹---复制主环境 2.Python -n venv +目录 注意须在win环境下 3.激活虚拟环境 目录\Scripts\activate ...

  9. ES6详解

    1.ES6新增了let命令,用来声明变量.它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效. const声明常亮,不可改变 2.变量的解构赋值 (1)数组的解构赋值: 以前,为 ...

  10. UI线程和work线程

    UI线程处理消息,比如重绘,响应键盘鼠标等等跟消息有关的处理. 而工作线程一般是你自己写的用来处理数据的,比如操作数据库等等.(work线程)