So I'm writing a set of interfaces and base objects for the c# persistence layer I wrote about last week. As you expect you have an interface every object for persistence must implement (IBaseEntity if you must know, it basically requires an implementation of an IsDirty property), some relevant exception classes, and then the base persister class. Here a CLR "limitation" raises its ugly head.

My persistence base class has a constructor that accepts a SQL connection string and four Save methods, all with the internal access modifier. As you may know this limits access to these methods to classes contained in the same assembly. This allows me to have, for example, a Person object which contains a collection of credit cards, then when the person object is saved it takes responsibility for creating a transaction, saving itself, then creating a credit card persister and iterating through the credit card collection, saving each credit card within the same transaction. Thus if a credit card save fails everything before that failure is rolled back.

The method signatures look something like

protected internal bool Save(object persistee)

which calls

protected internal bool Save(object persistee,
  string connectionString)

which opens a connection based on the connectionString then calls

protected internal bool Save(object persistee,
  SqlConnection connection)

which opens a transaction and finally calls

abstract protected internal bool Save(object persistee,
  SqlConnection connection, SqlTransaction transaction)

Each persister must implement the final overload of Save and provide a suitable implementation to save its object away. The myriad of Save methods provides easy functionality to do the nested saves I described above. However the problem comes in placing the base class. Ideally you would place the base class in the same assembly as the exceptions and interfaces necessary to support your persistence implementation.

However you cannot use abstract protected internal and expect a class from a different assembly to be able to provide an implementation for it. The internal access modifier trumps even the protected access modifier, as well as the abstract keyword making it impossible to correctly override the method from a different assembly, so you end up copying your base class into the assembly that will contain your persisters. It's almost enough to make you want C++'s friend functionality.