C#中Action<A>与Action<B>(B继承A)的合法转换方式咨询
解决方案
为什么直接转换会失败
Action<B>不能直接强制转换为Action<A>,这是因为委托的逆变特性有严格限制:虽然Action<T>是逆变类型,但C#不允许直接对已有的Action<TDerived>实例做显式强制转换,必须通过安全的委托包装或类型转换机制实现。
更优雅的实现方式
方式1:用Delegate.CreateDelegate实现零开销转换
这种方法直接复用原委托的目标对象和方法,没有额外lambda包装的性能开销:
public void Execute() { var convertedCallback = (Action<A>)Delegate.CreateDelegate(typeof(Action<A>), _callback.Target, _callback.Method); onCompleted += convertedCallback; // doing something specific. }
方式2:封装泛型扩展方法提升复用性
如果需要在多个场景做类似转换,可以封装通用扩展方法,让代码更简洁易读:
public static class DelegateExtensions { public static Action<TBase> ToBaseAction<TDerived, TBase>(this Action<TDerived> action) where TDerived : TBase { return arg => action((TDerived)arg); } }
在B类中调用:
public void Execute() { onCompleted += _callback.ToBaseAction<B, A>(); // doing something specific. }
方式3:调整基类设计,从根源避免转换
如果可以修改抽象类A的结构,改用泛型基类的方式,彻底消除委托转换的需求:
public abstract class A<T> where T : A<T> { protected event Action<T> onCompleted; public void CompleteExecution() { onCompleted?.Invoke((T)this); } } public class B : A<B> { private Action<B> _callback; public void Initialize(Action<B> callback) { _callback = callback; } public void Execute() { onCompleted += _callback; // doing something specific. } }
这种设计类型安全,代码最简洁,是最优的长期解决方案。
内容的提问来源于stack exchange,提问作者Apache81
相关产品推荐
相关产品推荐

