C#中如何实现同签名不同类型委托的引用赋值?
C# 中自定义委托属于强类型定义,即便方法签名完全一致,不同委托类型之间也不存在默认的隐式/显式转换,直接赋值会触发编译错误,可根据实际场景选择以下实现方式:
方案1:统一使用内置泛型委托(推荐,最简洁)
如果可以修改原有委托定义,直接删除冗余的自定义委托,全部使用.NET内置的Action<string>类型即可。该类型的签名为public delegate void Action<in T>(T obj),和你定义的三个委托完全匹配,同类型之间可直接赋值,从根源上规避类型不匹配问题,也是.NET开发的通用规范。
修改后的代码示例:
// 静态类部分修改 public static class StClass { public static Action<string> myD1 { get; set; } public static Action<string> myD2 { get; set; } } // MyClass部分修改 public class MyClass { public Action<string> myD { get; set; } public MyClass(bool condition) // 替换为你的实际判断逻辑 { if(condition) { myD = StClass.myD1; } else { myD = StClass.myD2; } } }
方案2:无法修改原有D1/D2定义时的适配写法
如果你没有权限修改StClass中已有的D1、D2委托定义,不需要自定义新的委托类型,直接用lambda表达式包装一层调用即可,编译器会自动完成适配,性能开销几乎可以忽略:
public class MyClass { public Action<string> myD { get; set; } public MyClass(bool condition) { if(condition) { myD = s => StClass.myD1?.Invoke(s); } else { myD = s => StClass.myD2?.Invoke(s); } } }
注意:如果你需要运行时读取StClass中myD1/myD2的最新赋值,上述写法可以直接满足;如果你需要固定构造时刻的委托引用,可先将静态委托赋值给本地变量再传入lambda。
方案3:必须保留MyClass内自定义D委托的实现
如果你因为业务要求必须保留MyClass中定义的D委托类型,赋值逻辑和方案2一致,直接通过lambda构造D类型的实例即可:
public class MyClass { public delegate void D(string s); public D myD { get; set; } public MyClass(bool condition) { if(condition) { myD = s => StClass.myD1?.Invoke(s); } else { myD = s => StClass.myD2?.Invoke(s); } } }
注意:不要尝试对不同类型的委托做强制类型转换,这类操作会在运行时抛出
InvalidCastException;也不需要使用反射、Delegate.CreateDelegate这类重型方案实现适配,lambda包装是可读性、性能最优的实现方式。C# 对不同自定义委托做类型隔离是刻意的强类型设计,目的是避免委托被随意混用引发逻辑问题,不要用奇技淫巧绕开该机制。
内容的提问来源于stack exchange,提问作者IoTid

