Я бы хотел определить интерфейс и абстрактный базовый класс для набора типов «Запись».Записи обычно передаются в / из другой системы, которая представляет запись в виде строки.Таким образом, каждому классу записи потребуется метод 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 инициализации на уровне базового класса есть свойственный недостаток?