泛型方法调用问题:通过类型设置T实现ILookupable与ILookupTable协作
问题描述
我定义了两个接口:ILookupable<T>(约束T实现ILookupTable)和ILookupTable,其中ILookupable<T>包含一个IList<T>类型的LookupTable属性。我写了一个处理ILookupable的服务,其中GetText<T>方法(约束T实现ILookupable<ILookupTable>)需要在传入的container的LookupTable为空时,调用GetLookupTable<T>方法(约束T实现ILookupTable)从数据库查询数据并赋值。但我没法实现这个逻辑,求一个无需反射的解决方案。
关键代码如下:
接口定义
public interface ILookupable<T> where T : ILookupTable { public int Id { get; set; } public IList<T> LookupTable { get; set; } = new List<T>(); } public interface ILookupTable { public int RefId { get; set;} // 其他成员 }
服务方法
protected string GetText<T>(T container, string lookup) where T : ILookupable<ILookupTable> { // 原有逻辑 if (!container.LookupTable.Any()) container.LookupTable = GetLookupTable<*需要具体LookupTable类型*>(container.Id); // 后续逻辑 } protected IList<T> GetLookupTable(int refId) where T : ILookupTable { // 数据库查询逻辑,返回List<T> }
无反射解决方案
核心问题是原GetText<T>的泛型约束丢失了具体的LookupTable类型信息——你只知道容器实现了ILookupable<ILookupTable>,但不知道实际的TLookup具体类型,因此无法直接匹配GetLookupTable<T>的泛型参数。以下是两种可行的无反射方案:
方案一:拆分泛型参数
修改GetText方法的定义,同时指定容器类型和对应的LookupTable类型:
protected string GetText<TContainer, TLookup>(TContainer container, string lookup) where TContainer : ILookupable<TLookup> where TLookup : ILookupTable { // 原有逻辑 if (!container.LookupTable.Any()) { // 现在可以明确传入TLookup作为泛型参数 container.LookupTable = GetLookupTable<TLookup>(container.Id); } // 后续逻辑处理 return "处理后的文本"; }
说明
- 拆分泛型参数后,
TLookup明确指向容器对应的具体LookupTable类型,编译器可以正确推导或接受该类型,直接调用GetLookupTable<TLookup>,完全不需要反射。 - 调用时编译器通常能自动推导类型,无需手动指定:
var myContainer = new SomeLookupableContainer(); // 假设实现了ILookupable<SomeLookupTable> var result = GetText(myContainer, "someLookupKey");
方案二:在接口中添加加载方法
在ILookupable<T>接口中定义加载LookupTable的抽象方法,让容器实现类自行处理加载逻辑:
public interface ILookupable<T> where T : ILookupTable { public int Id { get; set; } public IList<T> LookupTable { get; set; } = new List<T>(); // 添加加载方法 void LoadLookupTable(); }
然后在容器实现类中具体实现该方法:
public class SomeLookupableContainer : ILookupable<SomeLookupTable> { public int Id { get; set; } public IList<SomeLookupTable> LookupTable { get; set; } = new List<SomeLookupTable>(); public void LoadLookupTable() { LookupTable = GetLookupTable<SomeLookupTable>(Id); } }
此时GetText方法只需调用容器的加载方法即可:
protected string GetText<T>(T container, string lookup) where T : ILookupable<ILookupTable> { if (!container.LookupTable.Any()) container.LoadLookupTable(); // 后续逻辑 }
说明
这种方式把加载逻辑下沉到容器实现类,同样不需要反射,但需要每个容器类都实现LoadLookupTable方法。
内容的提问来源于stack exchange,提问作者Jason
相关产品推荐
相关产品推荐

