如何优化含公共成员的A、B类组合输入类C的属性同步实现?
首先得明确咱们的核心需求:让C类能统一设置InputBase里的公共属性,自动同步到内部的A和B实例,同时能方便获取这些属性,还要解决C类是否该继承InputBase的疑问。
先分析现有问题
当前C类只是简单包裹A和B的实例,导致更新公共属性时要分别操作c.A.DateCreated和c.B.DateCreated,不仅繁琐还容易漏改。咱们要做的就是把公共属性的操作入口统一到C类上,内部自动同步。
方案一:让C继承InputBase(推荐,支持多态)
如果你的服务里有接收InputBase类型的方法,或者希望C能和A、B保持统一的基类接口,那让C继承InputBase是最优解。通过重写基类的公共属性,在Setter里同步A和B的对应值,Getter直接取其中一个实例的属性(因为同步后两者值一致)。
代码示例:
public abstract class InputBase { public bool Option1 { get; set; } public decimal Rate { get; set; } public DateTime DateCreated { get; set; } } public class A : InputBase { public decimal Fee { get; set; } } public class B : InputBase { public decimal Fee { get; set; } } public class C : InputBase { // 自动初始化A和B实例,避免用户手动创建 public A A { get; set; } = new A(); public B B { get; set; } = new B(); // 重写基类公共属性,实现同步逻辑 public override bool Option1 { get => A.Option1; set { A.Option1 = value; B.Option1 = value; } } public override decimal Rate { get => A.Rate; set { A.Rate = value; B.Rate = value; } } public override DateTime DateCreated { get => A.DateCreated; set { A.DateCreated = value; B.DateCreated = value; } } }
这样使用起来就完全符合你的期望:
var c = new C(); c.DateCreated = DateTime.Now; // 统一设置,自动同步到A和B var createdDate = c.A.DateCreated; // 和c.DateCreated值一致
额外优化:防止外部修改A/B实例导致不一致
如果担心外部代码直接替换A或B的实例(比如c.A = new A();)导致属性不同步,可以把A和B的Setter设为私有,只保留Getter:
public A A { get; } = new A(); public B B { get; } = new B();
如果必须允许替换A/B实例,那在属性的Setter里补充同步逻辑:
private A _a = new A(); public A A { get => _a; set { _a = value; // 把当前C的公共属性同步到新的A实例 _a.Option1 = base.Option1; _a.Rate = base.Rate; _a.DateCreated = base.DateCreated; } } // B的Setter同理处理
方案二:C不继承InputBase(适合无需多态场景)
如果你的服务不需要C作为InputBase的子类,也可以在C类中直接定义和InputBase完全一致的公共属性,实现同样的同步逻辑:
public class C { public A A { get; set; } = new A(); public B B { get; set; } = new B(); public bool Option1 { get => A.Option1; set { A.Option1 = value; B.Option1 = value; } } public decimal Rate { get => A.Rate; set { A.Rate = value; B.Rate = value; } } public DateTime DateCreated { get => A.DateCreated; set { A.DateCreated = value; B.DateCreated = value; } } }
这个方案的用法和方案一完全一样,只是C不能当作InputBase来使用。
关于Getter的处理逻辑
因为我们在Setter里已经确保了A和B的公共属性值完全一致,所以Getter只需要取其中一个实例的属性即可(比如示例中的A)。如果要更严谨,可以在Getter里加个校验,确保A和B的属性值一致,避免外部直接修改A/B的属性导致不一致:
public override DateTime DateCreated { get { if (A.DateCreated != B.DateCreated) { // 可以抛出异常,或者统一取A的值,根据业务需求处理 throw new InvalidOperationException("A和B的DateCreated属性不一致"); } return A.DateCreated; } // Setter逻辑不变 }
总结最优实现方式
- 优先选择方案一:让C继承
InputBase,这样既能统一操作公共属性,又能支持多态,符合面向对象的设计原则。 - 自动初始化A/B实例:在C的属性初始化或构造函数中创建A和B的实例,避免用户手动编写繁琐的初始化代码。
- 控制A/B的修改权限:根据业务需求,决定是否允许外部替换A/B实例,若允许则补充同步逻辑,防止属性不一致。
内容的提问来源于stack exchange,提问作者ldam

