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

如何让抽象泛型类的外部引用保持抽象且泛型?

问题分析

你遇到的核心矛盾是:UserClass需要兼容任意Utility<A,B>实现,但不能将自身定义为泛型类,同时又不想通过object强制转换来处理A、B类型——这种方式不仅类型不安全,还可能带来不必要的性能损耗。

原代码的问题在于UserClass直接依赖泛型的Utility<A,B>,但自身并非泛型,导致A、B无法被正确解析;而单纯给Utility加非泛型接口,也无法解决UserClass需要获取并传递泛型数据的问题。

解决方案:封装泛型细节到非泛型接口

核心思路是用非泛型接口封装整个数据处理流程,把A、B的具体类型隐藏在接口实现内部,让UserClass只需要和非泛型接口交互,完全不需要感知泛型类型的存在。

步骤1:定义非泛型接口

先定义两个非泛型接口,分别对应全局处理和单行处理:

// 顶层接口:定义创建行处理器的能力
public interface IUtility
{
    // 传入全局参数foo,返回可处理单行数据的处理器
    IRowProcessor CreateRowProcessor(float foo);
}

// 行处理器接口:定义单行数据的处理能力
public interface IRowProcessor
{
    // 传入单行参数bar,返回处理后的结果
    float ProcessRow(float bar);
}

步骤2:改造泛型Utility类

让原有的泛型Utility<A,B>实现IUtility接口,并在内部封装A、B的处理逻辑:

public abstract class Utility<A, B> : IUtility
{
    public abstract A GetPrimaryData(float foo);
    public abstract B GetSecondaryData(float bar, A primaryData);
    public abstract float ProcessData(A primaryData, B secondaryData);

    public IRowProcessor CreateRowProcessor(float foo)
    {
        // 只获取一次primaryData,符合性能要求
        A primaryData = GetPrimaryData(foo);
        // 返回持有primaryData的闭包处理器
        return new RowProcessor(this, primaryData);
    }

    // 内部私有类,封装单行处理逻辑
    private class RowProcessor : IRowProcessor
    {
        private readonly Utility<A, B> _utility;
        private readonly A _primaryData;

        public RowProcessor(Utility<A, B> utility, A primaryData)
        {
            _utility = utility;
            _primaryData = primaryData;
        }

        public float ProcessRow(float bar)
        {
            B secondaryData = _utility.GetSecondaryData(bar, _primaryData);
            return _utility.ProcessData(_primaryData, secondaryData);
        }
    }
}

步骤3:修改UserClass

现在UserClass只需要依赖非泛型的IUtility,完全不需要关心A、B的类型:

public class UserClass
{
    public IUtility Utility;

    public void UseCase(Table table)
    {
        float foo = GetFoo(table);
        // 创建行处理器,内部已持有全局的primaryData
        var rowProcessor = Utility.CreateRowProcessor(foo);

        // 并行处理每行,直接调用行处理器的方法
        var stuffUserCaresAbout = table.AsParallel()
            .Select(row => rowProcessor.ProcessRow(GetBar(row)))
            .ToList();

        Consume(stuffUserCaresAbout);
    }

    // 原有业务方法保持不变
    private float GetFoo(Table table) => /* 你的实现 */;
    private float GetBar(Row row) => /* 你的实现 */;
    private void Consume(IEnumerable<float> results) => /* 你的实现 */;
}
方案优势
  • 类型安全:全程没有object强制转换,完全避免类型错误风险
  • 性能友好:保留了原逻辑中只获取一次primaryData的优化,且没有装箱拆箱开销
  • 解耦彻底:UserClass只依赖非泛型抽象接口,可兼容任意Utility<A,B>实现,符合依赖倒置原则
  • 代码简洁:把泛型细节完全封装在Utility内部,UserClass的逻辑更清晰

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 21:13:17