You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 14:40:18