能否将泛型委托存储在类型化列表中以避免强制转换?
嘿,我懂你现在的痛点——你用List<object>存储泛型委托,每次调用都得强制转换,想换成类型化列表来简化操作,但直接写List<dEvent<T>>总会报找不到T的错误,对吧?
为什么直接声明List<dEvent<T>>不行?
问题出在T的作用域上。你的dEvent<T>是泛型委托,但TestClass本身不是泛型类。当你在类里直接写List<dEvent<T>>时,编译器完全不知道这个T指代什么类型——它没有被定义为类的泛型参数,自然会抛出“未找到命名空间T”这类错误。
解决方案1:用Dictionary<Type, Delegate>按类型存储(推荐)
这种方法既能避免强制转换,又能提升调用时的效率(不用遍历整个列表),核心是用类型作为键,直接存储对应类型的泛型委托:
class TestClass { public delegate void dEvent<T>(object sender, T value); // 用字典按类型映射对应的泛型委托 private Dictionary<Type, Delegate> _eventDictionary = new Dictionary<Type, Delegate>(); public void Subscribe<T>(dEvent<T> ev) { var eventType = typeof(T); if (_eventDictionary.ContainsKey(eventType)) { // 支持多个同类型委托,合并它们 _eventDictionary[eventType] = Delegate.Combine(_eventDictionary[eventType], ev); } else { _eventDictionary.Add(eventType, ev); } } public void InvokeAll<T>(object sender, T value) { var eventType = typeof(T); if (_eventDictionary.TryGetValue(eventType, out var targetDelegate)) { // 直接转换为对应泛型委托并调用 (targetDelegate as dEvent<T>)?.Invoke(sender, value); } } static public void StringSubscriber(object sender, string value) { Debug.WriteLine(value); } static public void IntSubscriber(object sender, int value) { Debug.WriteLine(value); } static public void RunTest() { TestClass testClass = new TestClass(); testClass.Subscribe<string>(StringSubscriber); testClass.Subscribe<int>(IntSubscriber); // 可以添加多个同类型委托测试合并效果 // testClass.Subscribe<string>(sender => Debug.WriteLine("Another string handler!")); testClass.InvokeAll<string>(testClass, "Hello"); testClass.InvokeAll<string>(null, "World"); testClass.InvokeAll<int>(testClass, 4); testClass.InvokeAll<int>(null, 2); } }
这个方案的优势很明显:
- 调用时无需遍历整个列表,直接通过
Type查找,效率更高 - 避免了
object列表的类型不安全问题 - 支持多个同类型委托的订阅(通过
Delegate.Combine合并)
解决方案2:用非泛型接口包装泛型委托
如果你的场景中委托数量不多,也可以通过定义非泛型接口来统一类型,实现类型化存储:
// 定义非泛型接口,统一调用入口 public interface IEventWrapper { void Invoke(object sender, object value); } // 泛型包装类,将泛型委托适配到非泛型接口 public class EventWrapper<T> : IEventWrapper { private readonly TestClass.dEvent<T> _targetEvent; public EventWrapper(TestClass.dEvent<T> ev) { _targetEvent = ev; } public void Invoke(object sender, object value) { if (value is T typedValue) { _targetEvent?.Invoke(sender, typedValue); } } } class TestClass { public delegate void dEvent<T>(object sender, T value); // 存储非泛型接口实例,实现类型化存储 private List<IEventWrapper> _eventList = new List<IEventWrapper>(); public void Subscribe<T>(dEvent<T> ev) { var wrapper = new EventWrapper<T>(ev); if (!_eventList.Contains(wrapper)) { _eventList.Add(wrapper); } } public void InvokeAll<T>(object sender, T value) { foreach (var wrapper in _eventList) { wrapper.Invoke(sender, value); } } // 以下订阅方法和测试代码和你原来的一致 static public void StringSubscriber(object sender, string value) { Debug.WriteLine(value); } static public void IntSubscriber(object sender, int value) { Debug.WriteLine(value); } static public void RunTest() { TestClass testClass = new TestClass(); testClass.Subscribe<string>(StringSubscriber); testClass.Subscribe<int>(IntSubscriber); testClass.InvokeAll<string>(testClass, "Hello"); testClass.InvokeAll<string>(null, "World"); testClass.InvokeAll<int>(testClass, 4); testClass.InvokeAll<int>(null, 2); } }
这个方案通过包装类将泛型委托转换为非泛型接口实例,列表存储接口对象,调用时自动处理类型转换,避免了直接存储object的麻烦。
内容的提问来源于stack exchange,提问作者dm76752
相关产品推荐
相关产品推荐

