如何在C#泛型方法中访问未在接口定义的Id成员?
解决泛型类型访问Id成员的几种方案
方案1:扩展原有接口(推荐)
既然所有T类型都包含Id成员,最规范的做法是把Id加入到ITheObjectInterface中,同时给泛型方法加上接口约束,确保编译时类型安全:
修改接口:
public interface ITheObjectInterface { string? Id { get; set; } // 添加Id成员 } public class TheObject : ITheObjectInterface { public string? Id { get; set; } // 其他成员... }
在抽象服务类的泛型定义中添加约束:
public abstract class BaseService<T> where T : ITheObjectInterface { private readonly IMemoryCache _memoryCache; public BaseService(IMemoryCache memoryCache) { _memoryCache = memoryCache; } public async Task<T> GetAsync(string id) { if (!_memoryCache.TryGetValue(typeof(T).Name, out List<T>? dtoStuff)) { dtoStuff = new List<T>(); } return dtoStuff.FirstOrDefault(o => o.Id == id); // 可正常访问Id } }
方案2:使用反射(无接口修改时的临时方案)
如果无法修改原有接口,可通过反射获取Id属性的值,缺点是存在一定性能开销:
public async Task<T> GetAsync(string id) { if (!memoryCache.TryGetValue(typeof(T).Name, out List<T>? dtoStuff)) { dtoStuff = new List<T>(); } var idProperty = typeof(T).GetProperty("Id"); return dtoStuff.FirstOrDefault(o => idProperty?.GetValue(o)?.ToString() == id); }
方案3:使用动态类型(快速测试用)
利用dynamic绕过编译检查,但会丢失类型安全,仅适合临时测试场景:
public async Task<T> GetAsync(string id) { if (!memoryCache.TryGetValue(typeof(T).Name, out List<T>? dtoStuff)) { dtoStuff = new List<T>(); } return dtoStuff.FirstOrDefault(o => ((dynamic)o).Id == id); }
方案4:新增继承接口(兼容原接口的类型安全方案)
如果不想修改原接口,可新建包含Id的接口继承自ITheObjectInterface,让实体类实现新接口,同时调整泛型约束:
// 新增带Id的接口 public interface IIdentifiable : ITheObjectInterface { string? Id { get; set; } } // 修改实体类实现新接口 public class TheObject : IIdentifiable { public string? Id { get; set; } // 其他成员... } // 修改泛型约束 public abstract class BaseService<T> where T : IIdentifiable { // ... 原有代码,现在可直接访问o.Id }
内容的提问来源于stack exchange,提问作者Robert Achmann
相关产品推荐
相关产品推荐

