如何在C#中不使用接口模拟实现多重继承?
在.NET Framework中实现多功能包复用的几种方案
1. 扩展方法 + 接口(无状态/轻量逻辑首选)
针对XML版本兼容读写这类无状态或仅依赖接口约定的逻辑,扩展方法是最直接的复用方式。先定义标记接口,再通过扩展方法为接口添加默认实现,类只需实现接口就能复用这些逻辑,无需重复编写版本切换等通用代码。
示例:XML版本化读写
先定义核心接口,预留子类需实现的版本专属逻辑:
public interface IXmlSavable { int CurrentVersion { get; } void ReadVersion1(XElement element); void ReadVersion2(XElement element); XElement WriteVersion1(); XElement WriteVersion2(); }
编写扩展方法封装通用的版本切换逻辑:
public static class XmlSavableExtensions { public static void Read(this IXmlSavable savable, XElement root) { int version = int.TryParse(root.Attribute("Version")?.Value, out var v) ? v : 1; switch (version) { case 1: savable.ReadVersion1(root); break; case 2: savable.ReadVersion2(root); break; default: throw new NotSupportedException($"不支持的XML版本:{version}"); } } public static XElement Write(this IXmlSavable savable) { XElement root = savable.CurrentVersion switch { 1 => savable.WriteVersion1(), 2 => savable.WriteVersion2(), _ => throw new InvalidOperationException($"无效的当前版本:{savable.CurrentVersion}") }; root.SetAttributeValue("Version", savable.CurrentVersion); return root; } }
使用时,类只需实现版本专属方法,直接调用扩展方法即可:
public class UserData : IXmlSavable { public string Name { get; set; } public int Age { get; set; } public string Email { get; set; } // V2新增属性 public int CurrentVersion => 2; public void ReadVersion1(XElement root) { Name = root.Element("Name").Value; Age = int.Parse(root.Element("Age").Value); } public void ReadVersion2(XElement root) { ReadVersion1(root); // 复用V1逻辑 Email = root.Element("Email").Value; } public XElement WriteVersion1() { return new XElement("UserData", new XElement("Name", Name), new XElement("Age", Age)); } public XElement WriteVersion2() { var root = WriteVersion1(); root.Add(new XElement("Email", Email)); return root; } } // 调用示例 var user = new UserData(); user.Read(XElement.Load("user.xml")); user.Write().Save("user.xml");
2. 组合模式(有状态逻辑首选)
对于“暂停事件触发锁”这类需要维护内部状态(如暂停计数)的逻辑,组合模式比继承更灵活。将每个功能封装为独立的处理类,在目标类中通过成员变量引入这些处理类,实现对应的接口并委托调用处理类的方法。
示例:事件暂停锁
先封装事件暂停逻辑为独立类:
public class EventPauseManager { private int _pauseCount; public bool IsPaused => _pauseCount > 0; public void Pause() { Interlocked.Increment(ref _pauseCount); } public void Resume() { Interlocked.Decrement(ref _pauseCount); } // 辅助方法:判断是否允许触发事件 public bool CanTrigger() => _pauseCount == 0; }
定义对应的接口:
public interface IEventPausable { void PauseEvents(); void ResumeEvents(); }
在目标类中组合并实现接口:
public class OrderService : IEventPausable, IXmlSavable { private readonly EventPauseManager _pauseManager = new EventPauseManager(); private readonly XmlSavableHandler _xmlHandler; public event EventHandler<OrderEventArgs> OrderCreated; public OrderService() { _xmlHandler = new XmlSavableHandler(this); } // 实现IEventPausable接口 public void PauseEvents() => _pauseManager.Pause(); public void ResumeEvents() => _pauseManager.Resume(); public void CreateOrder(Order order) { // 业务逻辑... // 触发事件前判断是否暂停 if (_pauseManager.CanTrigger()) { OrderCreated?.Invoke(this, new OrderEventArgs(order)); } } // 委托XML处理逻辑给组合类 public int CurrentVersion => 1; public void ReadVersion1(XElement element) => _xmlHandler.ReadVersion1(element); public void ReadVersion2(XElement element) => throw new NotImplementedException(); public XElement WriteVersion1() => _xmlHandler.WriteVersion1(); public XElement WriteVersion2() => throw new NotImplementedException(); } // XML处理组合类示例 public class XmlSavableHandler { private readonly OrderService _target; public XmlSavableHandler(OrderService target) { _target = target; } public void ReadVersion1(XElement root) { // 读取XML数据到_target的属性 } public XElement WriteVersion1() { // 生成_target对应的XML元素 return new XElement("OrderService"); } }
3. 抽象类 + 接口组合(单一主逻辑继承,其他功能组合)
如果某个功能是类的核心逻辑,可以用抽象类封装,其他非核心功能用组合模式引入。比如业务类核心是XML可保存,就继承XmlSavableBase抽象类,同时组合EventPauseManager实现事件暂停功能。
public abstract class XmlSavableBase : IXmlSavable { public abstract int CurrentVersion { get; } public abstract void ReadVersion1(XElement element); public abstract void ReadVersion2(XElement element); public abstract XElement WriteVersion1(); public abstract XElement WriteVersion2(); // 封装版本切换逻辑(抽象类可直接实现接口方法) public void Read(XElement root) { int version = int.TryParse(root.Attribute("Version")?.Value, out var v) ? v : 1; switch (version) { case 1: ReadVersion1(root); break; case 2: ReadVersion2(root); break; default: throw new NotSupportedException($"不支持的XML版本:{version}"); } } public XElement Write() { XElement root = CurrentVersion switch { 1 => WriteVersion1(), 2 => WriteVersion2(), _ => throw new InvalidOperationException($"无效的当前版本:{CurrentVersion}") }; root.SetAttributeValue("Version", CurrentVersion); return root; } } // 业务类继承抽象类,同时组合其他功能 public class Product : XmlSavableBase, IEventPausable { private readonly EventPauseManager _pauseManager = new EventPauseManager(); public event EventHandler ProductUpdated; public override int CurrentVersion => 2; // 实现抽象类的版本读写方法... // 实现IEventPausable接口 public void PauseEvents() => _pauseManager.Pause(); public void ResumeEvents() => _pauseManager.Resume(); public void UpdateProduct() { // 业务逻辑... if (_pauseManager.CanTrigger()) { ProductUpdated?.Invoke(this, EventArgs.Empty); } } }
内容的提问来源于stack exchange,提问作者lhiapgpeonk
相关产品推荐
相关产品推荐

