C#中如何实现多所有权接口的函数与实现复用
解决方案:C# 中可组合的资源所有权实现
针对你遇到的「多资源所有权复用」问题,以下是几种简洁且符合C#设计习惯的实现方案:
方案1:正确使用C# 8+接口默认实现(推荐)
你之前的误区在于认为接口默认实现需要向下转型——实际上,接口默认实现可以直接访问自身定义的属性,只要实现类正确实现接口的属性,默认方法就能直接复用,无需重复编码。
public class A { public string Name { get; set; } = string.Empty; } public class B { public string Name { get; set; } = string.Empty; } // 带默认实现的A所有权接口 public interface IAOwner { List<A> AList { get; set; } // 默认实现直接访问接口定义的AList属性 public A? GetA(string name) { return AList.FirstOrDefault(a => a.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); } } // 带默认实现的B所有权接口 public interface IBOwner { List<B> BList { get; set; } public B? GetB(string name) { return BList.FirstOrDefault(b => b.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); } } // 同时拥有A和B的所有者类,只需实现属性,自动继承默认方法 public class ABFullOwner : IAOwner, IBOwner { public List<A> AList { get; set; } = new List<A>(); public List<B> BList { get; set; } = new List<B>(); // 自定义所有者专属逻辑 public void PerformOwnerTask() { // ... } } // 仅拥有A的所有者类 public class AOnlyOwner : IAOwner { public List<A> AList { get; set; } = new List<A>(); // 自动拥有GetA方法,无需重写 }
如果需要自定义某类所有者的查询逻辑,直接重写默认方法即可:
public class CustomAOwner : IAOwner { public List<A> AList { get; set; } = new List<A>(); // 重写默认实现,添加模糊匹配逻辑 public A? GetA(string name) { return AList.FirstOrDefault(a => a.Name.Contains(name, StringComparison.OrdinalIgnoreCase)); } }
优点:
- 完全复用通用逻辑,无重复代码
- 组合灵活,按需实现对应所有权接口
- 不受C#单继承限制
方案2:扩展方法(兼容C# 8之前版本)
如果项目使用的是C# 8以下版本,不支持接口默认实现,可以用扩展方法封装通用所有权逻辑:
public interface IAOwner { List<A> AList { get; set; } } public static class IAOwnerExtensions { public static A? GetA(this IAOwner owner, string name) { return owner.AList.FirstOrDefault(a => a.Name == name); } } public interface IBOwner { List<B> BList { get; set; } } public static class IBOwnerExtensions { public static B? GetB(this IBOwner owner, string name) { return owner.BList.FirstOrDefault(b => b.Name == name); } }
使用时,实现接口后直接调用扩展方法即可:
var owner = new AOnlyOwner(); var targetA = owner.GetA("TestA");
缺点:扩展方法无法被重写,若需自定义逻辑必须手动实现对应方法。
方案3:组合模式(封装所有权逻辑)
如果需要更严格的封装,或动态调整所有权组合,可以将所有权逻辑封装为独立类,通过组合而非继承实现:
// 封装A所有权逻辑的独立类 public class AOwnerLogic { public List<A> AList { get; set; } = new List<A>(); public A? GetA(string name) { return AList.FirstOrDefault(a => a.Name == name); } } // 封装B所有权逻辑的独立类 public class BOwnerLogic { public List<B> BList { get; set; } = new List<B>(); public B? GetB(string name) { return BList.FirstOrDefault(b => b.Name == name); } } // 同时拥有A和B的所有者类 public class ABFullOwner { private readonly AOwnerLogic _aOwner = new AOwnerLogic(); private readonly BOwnerLogic _bOwner = new BOwnerLogic(); // 暴露必要的属性和方法 public List<A> AList => _aOwner.AList; public A? GetA(string name) => _aOwner.GetA(name); public List<B> BList => _bOwner.BList; public B? GetB(string name) => _bOwner.GetB(name); // 自定义逻辑 public void DoOwnerWork() { // ... } }
优点:
- 所有权逻辑独立可复用、可单独测试
- 可隐藏内部列表,仅暴露必要方法
- 支持动态添加/移除所有权(比如通过构造函数注入逻辑类)
缺点:需要手动转发属性和方法,代码量略多,可通过代码生成工具简化。
内容的提问来源于stack exchange,提问作者Payton Doud
相关产品推荐
相关产品推荐

