C#类使用多个构造函数时如何避免初始化代码重复
问题原因
你之前的链式调用报错,核心是C#的类型继承转换规则限制:
- 子类
PaymentSupplierLitePaymentRequest继承自父类PaymentSupplierPaymentRequest,因此子类实例可以隐式转换为父类类型 - 反过来父类实例无法直接隐式/强制转换为子类类型(除非运行时实例本身就是子类类型)
你第二个构造函数的入参是父类类型,直接传给要求子类入参的构造函数,自然会触发类型转换错误。
解决方案
把两个构造函数的公共初始化逻辑抽离到一个接收父类参数的私有构造函数中,两个公开构造函数都通过this关键字链式调用这个私有构造函数即可,既消除重复代码,也不会出现类型转换问题。
完整调整后的代码如下:
public class GemPayPaymentRequestBuilder { private readonly string _merchantCode; private readonly string _installationId; private readonly string _version; private readonly string _paymentMethodMaskCode; private readonly string _orderDescription; private readonly long _amount; private readonly string _currency; private readonly string _email; private const byte Exponent = 2; private readonly string _orderCode; /// <summary> /// 私有构造函数:抽离所有公共初始化逻辑,入参为父类DTO,兼容两种请求类型 /// </summary> private GemPayPaymentRequestBuilder(PaymentSupplierPaymentRequest baseRequest) { _amount = (long)(baseRequest.Amount * (decimal)Math.Pow(10, Exponent)); _orderDescription = baseRequest.Description; _currency = baseRequest.Currency; _orderCode = $"{baseRequest.AccountId}_{DateTime.UtcNow.Ticks}"; } /// <summary> /// 处理强制要求传MerchantCode的Lite支付请求 /// </summary> public GemPayPaymentRequestBuilder(PaymentSupplierLitePaymentRequest paymentRequest) : this(paymentRequest as PaymentSupplierPaymentRequest) // 子类转父类是安全的隐式转换 { _merchantCode = paymentRequest.MerchantCode; } /// <summary> /// 处理普通支付请求,从配置中读取MerchantCode等参数 /// </summary> public GemPayPaymentRequestBuilder(PaymentSupplierPaymentRequest paymentRequest, string email, WorldPayMerchantConfig config) : this(paymentRequest) // 入参本身就是父类类型,直接传入 { _email = email; _merchantCode = config.MerchantCode; _installationId = config.InstallationId; _version = config.Version; _paymentMethodMaskCode = config.PaymentMethodMaskCode; } }
方案说明
- 完全消除重复代码:公共字段的赋值逻辑仅在私有构造函数中维护一次,后续修改公共逻辑只需要改一处
- 符合C#语法规范:利用子类到父类的安全隐式转换,不会出现运行时类型转换错误
- 兼容原有调用:两个公开构造函数的签名完全没有变化,上层业务代码不需要做任何调整
- 适配readonly字段约束:所有字段都是
readonly修饰,只能在构造函数链路中完成赋值,该方案完全满足这个约束,不会出现编译错误。不要尝试抽普通私有初始化方法的方案——普通实例方法无法给readonly字段赋值,会直接编译失败。
内容的提问来源于stack exchange,提问作者user17603119
相关产品推荐
相关产品推荐

