C#双泛型类中如何通过构造参数设置泛型Func<T,U>委托?
问题分析与解决方案
先还原你的代码场景(方便理解问题):
public class Worker { public static string Method_(int input) => input.ToString(); public static bool Method_(double input) => input > 0; // 更多T、U对应的静态方法重载 } public class MyClass<T, U> { private Func<T, U> _handler; // 正常工作的构造函数:编译器自动推断Method_的对应重载 public MyClass(Func<T, U> handler) { _handler = handler; } // 编译报错的构造函数:无法匹配Method_到Func<T,U> public MyClass(WorkType workType) { _handler = Worker.Method_; // 报错点 } } public enum WorkType { IntToString, DoubleToBool // 更多类型组合枚举值 }
一、解决第二个构造函数的编译错误
编译器报错的核心原因:泛型参数T、U与workType之间没有编译期绑定关系,编译器无法知道当前MyClass<T,U>的T、U对应哪一个Method_重载。要解决这个问题,需要通过反射动态绑定方法:
修改后的构造函数实现:
public MyClass(WorkType workType) { // 1. 建立workType到T、U类型的映射(如果需要用枚举区分) var typeMap = new Dictionary<WorkType, (Type InputType, Type OutputType)> { { WorkType.IntToString, (typeof(int), typeof(string)) }, { WorkType.DoubleToBool, (typeof(double), typeof(bool)) } }; if (!typeMap.TryGetValue(workType, out var typePair)) throw new ArgumentOutOfRangeException(nameof(workType)); // 2. 校验当前泛型参数与枚举对应的类型是否一致 if (typeof(T) != typePair.InputType || typeof(U) != typePair.OutputType) throw new InvalidOperationException($"当前泛型类型<T,U>与workType不匹配"); // 3. 反射获取对应静态方法并转换为委托 var method = typeof(Worker).GetMethod("Method_", new[] { typeof(T) }); if (method == null || method.ReturnType != typeof(U)) throw new InvalidOperationException($"找不到Worker中输入为{typeof(T)}、输出为{typeof(U)}的Method_方法"); _handler = (Func<T, U>)Delegate.CreateDelegate(typeof(Func<T, U>), method); }
如果不需要通过workType枚举区分,直接根据当前T、U类型查找方法,可以简化掉枚举映射的步骤,直接反射获取即可。
二、近百种组合的替代方案(避免滥用泛型)
你当前的泛型用法不算滥用,但直接用反射每次创建实例都会有性能损耗。针对近百种T、U、Worker组合,推荐以下两种高效方案:
1. 预注册委托字典(推荐)
提前把所有T、U对应的Func<T,U>委托注册到静态字典,后续直接从字典获取,避免重复反射:
public static class WorkerDelegateRegistry { private static readonly Dictionary<(Type InputType, Type OutputType), Delegate> _registry = new(); // 静态构造函数中批量注册所有组合(或手动注册) static WorkerDelegateRegistry() { Register<int, string>(Worker.Method_); Register<double, bool>(Worker.Method_); // 其他近百种组合... // 也可以用反射扫描Worker类的所有Method_方法自动注册,减少手动代码 } public static void Register<T, U>(Func<T, U> handler) { _registry[(typeof(T), typeof(U))] = handler; } public static Func<T, U> GetHandler<T, U>() { if (_registry.TryGetValue((typeof(T), typeof(U)), out var del)) return (Func<T, U>)del; throw new InvalidOperationException($"未注册输入为{typeof(T)}、输出为{typeof(U)}的处理委托"); } }
然后修改MyClass<T,U>的构造函数:
public MyClass() { _handler = WorkerDelegateRegistry.GetHandler<T, U>(); }
2. 泛型缓存工厂
利用泛型静态构造函数的特性(每个泛型实例仅执行一次),缓存对应的委托,避免重复反射:
public static class MyClassFactory { public static MyClass<T, U> Create<T, U>() { return new MyClass<T, U>(WorkerDelegateCache<T, U>.Handler); } // 内部静态类,每个T、U组合仅初始化一次 private static class WorkerDelegateCache<T, U> { public static readonly Func<T, U> Handler; static WorkerDelegateCache() { var method = typeof(Worker).GetMethod("Method_", new[] { typeof(T) }); if (method == null || method.ReturnType != typeof(U)) throw new InvalidOperationException($"找不到Worker中匹配<T,U>的Method_方法"); Handler = (Func<T, U>)Delegate.CreateDelegate(typeof(Func<T, U>), method); } } }
使用时直接通过工厂创建实例:
var myInstance = MyClassFactory.Create<int, string>();
内容的提问来源于stack exchange,提问作者BoCoKeith
相关产品推荐
相关产品推荐

