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

如何实现每个键对应不同泛型类型的泛型委托字典?

实现类型安全的多类型泛型委托字典

要实现每个键对应不同T类型的Func<T,T>委托集合,同时保持编译时类型安全,可以通过非泛型基类+泛型子类+自定义集合封装的方式实现,完全避免object强制转换或dynamic的问题。

步骤1:定义转换委托的封装类

首先创建一个非泛型抽象基类,作为字典存储的统一类型;再实现泛型子类来封装具体的Func<T,T>委托,同时提供类型安全的调用入口:

public abstract class TypedTransformer
{
    // 非泛型调用入口(内部使用,外部无需直接调用)
    public abstract object Invoke(object input);
}

public class Transformer<T> : TypedTransformer
{
    private readonly Func<T, T> _transformFunc;

    public Transformer(Func<T, T> transformFunc)
    {
        _transformFunc = transformFunc ?? throw new ArgumentNullException(nameof(transformFunc));
    }

    // 实现基类的非泛型方法,内部做类型校验
    public override object Invoke(object input)
    {
        if (!(input is T typedInput))
            throw new ArgumentException($"输入必须是{typeof(T).Name}类型", nameof(input));
        
        return _transformFunc(typedInput);
    }

    // 外部调用的类型安全方法
    public T Invoke(T input) => _transformFunc(input);
}

步骤2:自定义类型安全的字典集合

封装一个专用的字典类,提供类型安全的Add和Invoke方法,确保操作时的类型正确性:

public class TransformerDictionary
{
    private readonly Dictionary<string, TypedTransformer> _innerDict = new Dictionary<string, TypedTransformer>();

    /// <summary>
    /// 添加指定类型的转换委托
    /// </summary>
    /// <typeparam name="T">委托的输入输出类型</typeparam>
    /// <param name="key">关联的字符串键</param>
    /// <param name="transformFunc">输入输出为T的转换委托</param>
    public void Add<T>(string key, Func<T, T> transformFunc)
    {
        if (string.IsNullOrWhiteSpace(key))
            throw new ArgumentException("键不能为空或空白", nameof(key));
        if (transformFunc == null)
            throw new ArgumentNullException(nameof(transformFunc));
        if (_innerDict.ContainsKey(key))
            throw new ArgumentException($"键{key}已存在", nameof(key));

        _innerDict.Add(key, new Transformer<T>(transformFunc));
    }

    /// <summary>
    /// 调用指定键的转换委托
    /// </summary>
    /// <typeparam name="T">委托的输入输出类型</typeparam>
    /// <param name="key">关联的字符串键</param>
    /// <param name="input">输入参数</param>
    /// <returns>转换后的结果</returns>
    public T Invoke<T>(string key, T input)
    {
        if (!_innerDict.TryGetValue(key, out var transformer))
            throw new KeyNotFoundException($"未找到键{key}");
        if (!(transformer is Transformer<T> typedTransformer))
            throw new InvalidOperationException($"键{key}对应的委托类型不是{typeof(T).Name}");

        return typedTransformer.Invoke(input);
    }
}

步骤3:使用示例

这个集合可以安全地存储不同类型的转换委托,调用时必须指定正确的类型,编译时就能检查类型错误:

var transformerDict = new TransformerDictionary();

// 添加不同类型的转换逻辑
transformerDict.Add<int>("翻倍", x => x * 2);
transformerDict.Add<string>("转大写", s => s.ToUpperInvariant());
transformerDict.Add<DateTime>("加一天", dt => dt.AddDays(1));

// 类型安全地调用
int doubled = transformerDict.Invoke<int>("翻倍", 5); // 结果:10
string upperStr = transformerDict.Invoke<string>("转大写", "hello"); // 结果:"HELLO"
DateTime tomorrow = transformerDict.Invoke<DateTime>("加一天", DateTime.Today); // 结果:明天的日期

方案优势

  • 编译时类型安全:添加和调用都明确指定T,类型不匹配的错误会在编译阶段暴露,而非运行时。
  • 避免繁琐转换:内部自动处理类型校验和转换,外部调用无需手动强制转换object。
  • 比dynamic更可靠:所有类型逻辑都是显式的,不会出现动态类型的意外行为,长期维护更稳定。

内容的提问来源于stack exchange,提问作者Dobby1235

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 13:00:30