如何让抽象泛型类的外部引用保持抽象且泛型?
问题分析
你遇到的核心矛盾是: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
相关产品推荐
相关产品推荐

