Internal constructors in the C # library

I am writing a data access library in C #, the structure of my data model classes is as follows (in the DataAccess assembly):

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 the Store data model which contains the Customer data class and the Employee data class generates this code:

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, which means that anyone outside of the assembly access to data can instantiate them, and I would like to prevent this.

Since the field classes have different constructors, I can't think of a way to use reflection or generics to create fields in the underlying data access assembly.

The only way I could think of is to add an "Initialize" method to each field class that will include the properties of those particular fields, and in the constructor of the custom data classes, do this:

   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 constructors of the fields to internal and prevent anyone from instantiating the field. The problem with this solution is that it will allow anyone to run the "Initialize" method and change the field (this can be solved by adding a private boolean (m_IsInitialized) that will be set to true when "Initialize" is first run, and each time, when "Initialize" is called, if m_IsInitialized is true, it will throw an exception, but this solution is a bit ugly).

Does anyone have a better solution?

+1


source to share


1 answer


Well, three options:

  • Use InternalsVisibleTo to make constructors visible
  • Write static methods to StringField, etc. to create instances
  • Write protected methods to DataModel or DataClass to instantiate fields (so CustomerDataClass could call DataClass.CreateStringField, etc.)


However, I don't know if any of these are acceptable, because it's not clear to me why you don't want the field classes to have public constructors.

+3


source







All Articles