I have written CodeFirstWebFramework, which is a dll providing all the tools to write a database driven web server, with the tables automatically generated from classes in the code, and gluing urls to calls to methods in AppModule classes.
The DLL provides some base AppModule classes - AdminModule and FileSender. These implement administration (logging on, maintaining users, updating settings), and returning files when the url does not relate to any other AppModule.
Consumers of the DLL can override the abstract AppModule class to add additional functionality to all their own AppModules (which will be derived from the override).
I would also like them to be able to override AdminModule and/or FileSender. However it would be useful (and, in some cases, essential) for them to be able to override one of these modules (thus having access to the default code therein), while also subclassing their own AppModule implementation.
I thought I had had a brilliant idea, as follows:
In my DLL:
abstract class AppModule {
// Contains base class implementation, including virtual Database property, code to
// retrieve files, code to call appropriate method depending on url, code to collect
// result and return it to the web browser, etc.
}
abstract class AdminModule<T> where T:AppModule, new() : T {
// Contains implementation of Admin methods - create/edit users,
// edit settings, backup database, etc.
}
class AdminModule : AdminModule<AppModule> {
// No code needed - inherits implementation from AdminModule<AppModule>
}
In the consumer program (different Namespace):
abstract class AppModule : AppModule {
// Contains additional properties and methods. Also overides some virtual methods,
// e.g. returns a subclass of Database with additional methods, or retrieve files
// from the database instead of the file system.
}
class AdminModule : AdminModule<AppModule> {
// Additional code for Admin methods specific to this application
// Does not need code for methods in base class - inherits implementation from
// AdminModule<AppModule>
}
In this particular instance, because of the constraint that T is an AppModule, and because AdminModule<T> is itself abstract, I can't see any reason why any of the objections raised so far would apply.
The compiler could check that any abstract methods were implemented in derived classes. There would be no danger of constructing an AdminModule<T>, because it is abstract.
It would be a compile-time error to write AdminModule<T> if T was a sealed class, or derived from AdminModule<T>, or has less accessibility than AdminModule<T>.