【问题标题】:internal constructors in a C# libraryC# 库中的内部构造函数
【发布时间】:2009-01-09 12:49:42
【问题描述】:

我正在用 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 文件自动生成类, 例如,包含“Customer”数据类和“Employee”数据类的“Store”数据模型将生成以下代码:

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/... 类必须具有公共构造函数,这意味着数据访问程序集之外的任何人都可以创建他们的实例,我想防止这种情况发生。

由于字段类具有不同的构造函数,我想不出使用反射或泛型在基础数据访问程序集中创建字段的方法。

我能想到的唯一方法是向每个字段类添加一个“初始化”方法,该方法将包含该特定字段的属性,并在自定义数据类构造函数中执行以下操作:

   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)来解决,该成员将在“Initialize”第一次运行时设置为true,并且每次调用“Initialize”时,如果m_IsInitialized为真,就会抛出异常,不过这个方案有点丑)。

谁有更好的解决方案?

【问题讨论】:

  • 更不用说,如果你在构造函数之外进行初始化,你将失去类不变量的保证,因为你依赖调用者来“帮助”对象构造。但我不是 C# 程序员,所以我真的帮不上忙。 :)

标签: c# inheritance


【解决方案1】:

嗯,三个选项:

  • 使用 InternalsVisibleTo 使构造函数可见
  • 在 StringField 等中编写静态方法来创建实例
  • 在 DataModel 或 DataClass 中编写受保护的方法来创建字段实例(因此 CustomerDataClass 可以调用 DataClass.CreateStringField 等)

但是,我不知道这些是否可以接受,因为我不清楚您为什么不希望字段类具有公共构造函数。

【讨论】:

  • 首先,我不想在字段类上放置公共构造函数的原因是没有人会尝试创建一个新字段并在其余代码中使用某处(不太可能,但仍然...) - InternalsVisibleTo 强制数据访问程序集知道自定义数据模型程序集。 ...
  • - 静态方法将允许任何人创建字段 - 我虽然是这样,但每当我添加另一个字段类时,我都需要编辑 DataClass 类......这不是最干净的方式。
  • "InternalsVisibleTo" 对我没有帮助,因为数据访问程序集是一个通用库,将用于各种项目。要使用它,我必须为每个新项目修改数据访问程序集(添加另一个 InternalsVisibleTo 属性)
  • 您还没有解释为什么不希望其他程序集创建实例。
  • 哦,我不希望任何用户创建字段类的实例,然后尝试将其与其余代码一起使用(用户的字段类可以是不存在的字段并且搞砸系统)。我想确定除了我之外没有人可以创建字段
猜你喜欢
  • 2018-03-07
  • 1970-01-01
  • 1970-01-01
  • 2022-11-26
  • 1970-01-01
  • 1970-01-01
  • 2011-04-16
  • 1970-01-01
  • 2021-08-13
相关资源
最近更新 更多