在写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. apache结合svn创建svn资源库

    1.在登录过程中可以查看error日志,如果发生以下提示: (13)Permission denied: Could not open password file 2.运行:chcon -R -h - ...

  2. rpm常用命令

    * 手动安装 rpm 包  `rpm-ivh xxxxx.rpm`  参数:   --force 即使覆盖其他包的文件也没强迫安装   --nodeps 即使依赖包没安装,也被强制安装 * 查看 rp ...

  3. 2-5. Working with Compile Time Constants

    #include <array> #include <cstdint> #include <iostream> class MyClass { private: u ...

  4. XE3随笔16:将字符串转换成 UTF8 编码的函数

    这种转换一般用于网页地址; 我不知道 Delphi 是不是有现成的函数, 用到了就写了一个. //函数: function ToUTF8Encode(str: string): string; var ...

  5. 解决服务器Active&nbsp;Directory环境里Windows登录性能问题办法

    Windows登录性能因素 当查找登录性能问题的原因时,考虑大量因素很重要.一些因素包括: 域控制器太接近用户 网络连接与可用的带宽 数据中心上的硬件资源(x64 vs.x86.内存等) 应用于用户和 ...

  6. prism4 StockTrader RI 项目分析一些体会

    StockTrader RI 代码分析也有一段时间了 刚从codeplex获取到源代码的时候,看得一头雾水,不知所云(因为之前没做过wpf的项目,看文档也静不下那心来看) 后来就想了个笨办法,模拟项目 ...

  7. ready与onload区别一

    <!DOCTYPE html><html> <head> <title>ready与onload区别一</title> <meta c ...

  8. html5 上传头像的裁剪

    本示例使用HTML5 canvas,简单的编写了上传头像的裁剪效果,移动端支持拖拽后裁剪, 虽然样式不好看,但是功能还算全: 下图为裁剪后的效果: html部分: <!DOCTYPE html& ...

  9. 前端js 判断输入的必须是数字,判断金钱

    //输入的必须是数字 $(".xzjl").on("keyup", ".num", function () { var v = $(this ...

  10. spring的beans.xml中classpath

    classpath就是代表 /WEB-INF /classes/ 这个路径(如果不理解该路径,就把一个web工程发布为war包,然后用winrar查看其包内路径就理解啦) 常用的场景: 在SSH架构中 ...