如何在Dictionary初始化过程中直接声明事件?
问题解答
很遗憾,C#并不支持你想要的{EventTypes.Event1, new event EventDelegate Event1}这种写法——事件是类级别的成员,必须在类的作用域内显式声明,不能在集合初始化器这类表达式上下文里临时创建或定义。
为什么不行?
事件本质是对委托的封装,它包含add和remove访问器,背后对应一个私有的委托字段。C#语法规定,事件只能作为类/结构体的成员来声明,无法通过new event这种语法在初始化器里实例化或定义。你尝试的写法既不符合事件的声明规则,也超出了集合初始化器的语法范围。
替代方案
如果你想减少重复代码,避免先声明事件再手动添加到字典的繁琐,有两种常见思路:
1. 用字典管理委托,封装事件式的访问
放弃单独声明每个事件,直接用字典存储委托实例,然后提供订阅、取消订阅和触发的方法,模拟事件的行为:
public delegate void EventDelegate(EventArgs args); public enum EventTypes { Event1, Event2, Event3 } private static readonly Dictionary<EventTypes, EventDelegate> _events = new Dictionary<EventTypes, EventDelegate> { { EventTypes.Event1, null }, { EventTypes.Event2, null }, { EventTypes.Event3, null }, }; // 模拟事件的订阅 public static void Subscribe(EventTypes eventType, EventDelegate handler) { if (_events.TryGetValue(eventType, out var existing)) { _events[eventType] = existing + handler; } } // 模拟事件的取消订阅 public static void Unsubscribe(EventTypes eventType, EventDelegate handler) { if (_events.TryGetValue(eventType, out var existing)) { _events[eventType] = existing - handler; } } // 触发事件 public static void RaiseEvent(EventTypes eventType, EventArgs args) { _events[eventType]?.Invoke(args); }
这种方式的好处是不需要重复声明每个事件,所有事件都通过字典统一管理,缺点是无法使用C#原生的+=/-=事件订阅语法。
2. 保留原生事件,简化字典初始化(可选)
如果你想保留原生事件的语法支持,也可以通过反射来自动把事件添加到字典,避免手动逐个添加:
public delegate void EventDelegate(); public enum EventTypes { Event1, Event2, Event3 } public static event EventDelegate Event1; public static event EventDelegate Event2; public static event EventDelegate Event3; public static readonly Dictionary<EventTypes, EventDelegate> Events; static YourClassName() { Events = new Dictionary<EventTypes, EventDelegate>(); // 通过反射获取所有静态事件 var events = typeof(YourClassName).GetEvents(BindingFlags.Public | BindingFlags.Static); foreach (var evt in events) { if (Enum.TryParse<EventTypes>(evt.Name, out var eventType)) { // 获取事件的委托实例 var field = typeof(YourClassName).GetField(evt.Name, BindingFlags.NonPublic | BindingFlags.Static); if (field != null) { Events[eventType] = field.GetValue(null) as EventDelegate; } } } }
这种方式保留了原生事件的+=/-=语法,同时自动完成字典的初始化,但反射会带来一点点性能开销,且代码复杂度稍高。
总结
直接在字典初始化器里声明事件的写法在C#中是不可行的,但你可以根据需求选择上述两种替代方案:要么用字典封装事件行为,要么用反射简化原生事件到字典的映射。
内容的提问来源于stack exchange,提问作者Nidere
相关产品推荐
相关产品推荐

