Я пишу библиотеку доступа к данным на C #, структура классов моей модели данных выглядит следующим образом (в сборке DataAccess):
public abstract class DataModel {...} (protected constructor)
public abstract class DataClass {...} (protected constructor)
public abstract class DataField {...} (protected constructor)
public class IntegerField : DataField
{
public IntegerField(DataClass cls, string name, bool isNullable,
int? defaultValue, int? minValue, int? maxValue) {...}
}
public class StringField : DataField
{
public StringField(DataClass cls, string name, bool isNullable,
string defaultValue, int maxLength) {...}
}
public class BooleanField : DataField
{
public BooleanField(DataClass cls, string name, bool isNullable,
bool? defaultValue) {...}
}
...
Как видите, у каждого поля свой конструктор.
Чтобы использовать это, вы автоматически генерируете классы из файла XML,
например, модель данных «Store», которая содержит класс данных «Customer» и класс данных «Employee», сгенерирует этот код:
public class StoreDataModel : DataModel
{
public CustomerDataClass Customer { get; private set;}
public EmployeeDataClass Employee { get; private set;}
public StoreDataModel()
{
Customer = new CustomerDataClass(this);
AddClass(customer)
Employee = new EmployeeDataClass(this);
AddClass(employee)
}
}
public class CustomerDataClass : DataClass
{
public StringField FirstNameField { get; private set; }
public StringField LastNameField { get; private set; }
public DateField BirthDateField { get; private set; }
public CustomerDataClass(StoreDataModel model) : base(model)
{
FirstNameField = new StringField(this, "FirstName", true, null, 50);
LastNameField = new StringField(this, "LastName", true, null, 50);
...
}
}
public class EmployeeDataClass : DataClass {...}
Моя проблема с этим кодом заключается в том, что поскольку сгенерированный код находится в сборке, отличной от базовых классов модели данных, классы StringField / IntegerField / ... должны иметь открытые конструкторы, и это означает, что любой, кто находится вне сборки доступа к данным, может создавать экземпляры их, и я хотел бы предотвратить это.
Поскольку классы полей имеют разные конструкторы, я не могу придумать, как использовать отражение или обобщенные элементы для создания полей в базовой сборке доступа к данным.
Единственный способ, о котором я мог подумать, - это добавить метод «Initialize» к каждому классу поля, который бы включал свойства этих конкретных полей, и в конструкторе пользовательского класса данных сделать это:
public CustomerDataClass(StoreDataModel model) : base(model)
{
FirstNameField = AddField<StringField>(this, "FirstName", true, null)
.Initialize(50);
LastNameField = AddField<StringField>(this, "LastName", true, null)
.Initialize(50);
...
}
Это позволит мне изменить конструкторы полей на внутренние и не позволит никому создавать экземпляр поля. Проблема с этим решением состоит в том, что он позволит любому запустить метод «Initialize» и изменить поле (это можно решить, добавив закрытый логический член (m_IsInitialized), который будет установлен в значение true при первом запуске «Initialize», и каждый раз, когда вызывается «Initialize», если m_IsInitialized имеет значение true, оно вызывает исключение, но это решение немного уродливо).
У кого-нибудь есть лучшее решение?