I'm writing a data access library in C#, the structure of my data model classes are as follows (within the DataAccess assembly):
我正在用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) {...}
}
...
As you can see, each field has a different constructor.
如您所见,每个字段都有不同的构造函数。
To use this you automatically generate classes from an XML file, for example, a "Store" data model, which contains a "Customer" data class and an "Employee" data class will generate this code:
要使用它,您可以自动从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 {...}
My problem with this code is that since the generated code is in a different assembly than the base data model classes, the StringField/IntegerField/... classes must have public constructors and that means anyone outside the data access assembly can create instances of them and I would like to prevent that.
我对此代码的问题在于,由于生成的代码与基本数据模型类位于不同的程序集中,因此StringField / IntegerField / ...类必须具有公共构造函数,这意味着数据访问程序集之外的任何人都可以创建它们的实例而我想阻止这一点。
Since the field classes have different constructors I can't think of a way to use reflection or generics to create the fields within the base data access assembly.
由于字段类具有不同的构造函数,因此我无法想到使用反射或泛型在基础数据访问程序集中创建字段的方法。
The only way I could think of was add a "Initialize" method to each field class that would include the properties of that specific fields and in the custom data class constructor do this:
我能想到的唯一方法是为每个字段类添加一个“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);
...
}
This will allow me to change the field constructors to internal and won't allow anyone to create an instance of a field. The problem with this solution is that it would allow anyone to run the "Initialize" method and alter the field (this can be solved by adding a private boolean member (m_IsInitialized) that will be set to true when "Initialize" is first run, and each time "Initialize" is called, if m_IsInitialized is true, it will throw an exception, but this solution is a little ugly).
这将允许我将字段构造函数更改为internal,并且不允许任何人创建字段的实例。这个解决方案的问题是它允许任何人运行“Initialize”方法并改变字段(这可以通过添加一个私有布尔成员(m_IsInitialized)来解决,当第一次运行“Initialize”时,该成员将设置为true,并且每次调用“Initialize”时,如果m_IsInitialized为true,则会抛出异常,但这个解决方案有点难看)。
Does anyone have a better solution?
有没有人有更好的解决方案?
1 个解决方案
#1
Well, three options:
好吧,有三种选择:
- Use InternalsVisibleTo to make the contructors visible
- Write static methods in StringField etc to create instances
- Write protected methods in DataModel or DataClass to create field instances (so CustomerDataClass could call DataClass.CreateStringField etc)
使用InternalsVisibleTo使构造函数可见
在StringField等中编写静态方法来创建实例
在DataModel或DataClass中编写受保护的方法以创建字段实例(因此CustomerDataClass可以调用DataClass.CreateStringField等)
However, I don't know whether any of these is acceptable because it's not clear to me why you don't want the field classes to have public constructors anyway.
但是,我不知道这些是否可以接受,因为我不清楚为什么你不希望字段类有公共构造函数。
#1
Well, three options:
好吧,有三种选择:
- Use InternalsVisibleTo to make the contructors visible
- Write static methods in StringField etc to create instances
- Write protected methods in DataModel or DataClass to create field instances (so CustomerDataClass could call DataClass.CreateStringField etc)
使用InternalsVisibleTo使构造函数可见
在StringField等中编写静态方法来创建实例
在DataModel或DataClass中编写受保护的方法以创建字段实例(因此CustomerDataClass可以调用DataClass.CreateStringField等)
However, I don't know whether any of these is acceptable because it's not clear to me why you don't want the field classes to have public constructors anyway.
但是,我不知道这些是否可以接受,因为我不清楚为什么你不希望字段类有公共构造函数。