如何避免重复实现多泛型参数的SimpleEvent通知类?
避免泛型事件类的代码重复方案
你当前的SimpleEvent<T>和SimpleEvent<T,Y>核心逻辑完全一致,仅因泛型参数数量不同导致代码冗余,以下几种方案可解决这个问题:
方案一:用元组统一泛型参数
利用C#的元组特性,将多参数场景封装为单一元组类型,只需要维护一个SimpleEvent<T>类即可覆盖单参数、多参数的需求:
public class SimpleEvent<T> { private event Action<T> listeners; private T storedValue; public void AddListener(Action<T> listener, bool notifySender = false) { listeners += listener; if (notifySender && storedValue != null) listener?.Invoke(storedValue); } // 补充更新存储值并触发事件的方法(原代码缺失,是事件类的必要功能) public void Trigger(T value) { storedValue = value; listeners?.Invoke(value); } }
使用示例
- 单参数场景:
var intEvent = new SimpleEvent<int>(); intEvent.AddListener(num => Console.WriteLine($"收到数值:{num}")); intEvent.Trigger(100);
- 双参数场景(利用元组解构):
var tupleEvent = new SimpleEvent<(string Msg, int Count)>(); // C# 7.0+支持直接解构元组参数 tupleEvent.AddListener((msg, count) => Console.WriteLine($"消息:{msg},计数:{count}")); tupleEvent.Trigger(("Hello", 5));
方案二:抽象基类抽取公共逻辑
如果需要保留SimpleEvent<T>和SimpleEvent<T,Y>的原有类名结构,可以将重复的核心逻辑抽离到抽象基类中,子类仅实现参数相关的差异部分:
// 抽象基类:封装添加监听器的公共逻辑 public abstract class BaseSimpleEvent { protected abstract void RegisterListener(object listener, bool notifyImmediately); public void AddListener(object listener, bool notifySender = false) { RegisterListener(listener, notifySender); } } // 单参数子类 public class SimpleEvent<T> : BaseSimpleEvent { private event Action<T> listeners; private T storedValue; protected override void RegisterListener(object listener, bool notifyImmediately) { var action = listener as Action<T>; if (action == null) return; listeners += action; if (notifyImmediately && storedValue != null) action.Invoke(storedValue); } public void Trigger(T value) { storedValue = value; listeners?.Invoke(value); } } // 双参数子类 public class SimpleEvent<T, Y> : BaseSimpleEvent { private event Action<T, Y> listeners; private (T, Y) storedValues; protected override void RegisterListener(object listener, bool notifyImmediately) { var action = listener as Action<T, Y>; if (action == null) return; listeners += action; if (notifyImmediately && storedValues.Item1 != null && storedValues.Item2 != null) action.Invoke(storedValues.Item1, storedValues.Item2); } public void Trigger(T tValue, Y yValue) { storedValues = (tValue, yValue); listeners?.Invoke(tValue, yValue); } }
方案对比
- 方案一更简洁,无需维护多个类,利用C#语言特性减少冗余,适合大多数场景;
- 方案二保留了原有类的命名习惯,兼容已有代码的调用方式,但需要维护基类和子类结构。
内容的提问来源于stack exchange,提问作者Deprion
相关产品推荐
相关产品推荐

