我想为一组“Record”类型定义一个接口和抽象基类。记录通常传递给另一个系统,该系统将记录表示为字符串。因此,每个记录类都需要Parse(string str)
方法和ToString()
方法。记录类还需要定义比较相等性的方法,以及一些其他常用的实用方法。没有公共基数的示例记录类可能如下所示:
public class MyRecord : IEquatable<MyRecord>
{
public string FieldA { get; private set; }
public int FieldB { get; private set; }
public MyRecord(string fieldA, int fieldB /* .. */) { }
public static MyRecord Parse(string recordString) { /* .. */ }
public override string ToString() { /* .. */ }
public override int GetHashCode() { /* .. */ }
public override bool Equals(object obj) { /* .. */ }
public bool Equals(MyRecord other) { /* .. */ }
}
如果我可以将记录设计为不可变的,它将简化使用场景。上面的类通过定义只读属性,并在参数化构造函数或Parse
方法中执行所有对象初始化来支持不可变性。我特意没有暴露默认构造函数。
我无法将此设计应用于具体记录类型可以继承的基本记录类。具体来说,我需要一个可以实例化派生类型的通用Parse
方法,而不暴露默认构造函数或部分构造的对象。到目前为止我的设计看起来像:
public interface IRecord { /* .. */ }
public abstract class RecordBase : IRecord
{
public static TRecord Parse<TRecord>(string recordStr)
where TRecord: RecordBase, new()
{
TRecord record = new TRecord();
record.Initialize(recordStr);
return record;
}
protected abstract void Initialize(string recordStr);
}
public class MyRecord : RecordBase, IEquatable<MyRecord>
{
public string FieldA { get; private set; }
public int FieldB { get; private set; }
public MyRecord(string fieldA, int fieldB /* .. */) { /* .. */ }
public override string ToString() { /* .. */ }
public override int GetHashCode() { /* .. */ }
public override bool Equals(object obj) { /* .. */ }
public bool Equals(MyRecord other) { /* .. */ }
protected MyRecord() { }
protected override void Initialize(string recordStr) { /* .. */ }
}
但是,当我尝试调用RecordBase.Parse<MyRecord>(..)
时,编译器会抱怨,因为MyRecord
的默认构造函数未公开显示。
所以我的问题是:
Parse
初始值设定项?或者在尝试使用基类级别的公共初始化API创建不可变类型层次结构时是否存在固有缺陷?答案 0 :(得分:2)
在为记录添加解析函数时,您正在破坏SRP。
答案 1 :(得分:0)
我认为您正在寻找工厂模式(数据解析)和奇怪的重复模板模式(克隆/工厂能力)。
E.g。
abstract class Base<T> : IBase // IBase for common demoninator
{
abstract T Parse(Stream data);
}
Derived : Base<Derived>
{
}
答案 2 :(得分:0)
如果您保证要非常小心,您可以使用System.Runtime.Serialization.FormatterServices.GetUninitializedObject。但是,使用此方法需要保证所有IRecord.Parse实现都不希望任何字段(根本不是)为null / 0.