This post is in continuation of this one.
I am trying to understand if I am the only one who misses and needs the ability of a .NET generic type to inherit one of it
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>.
The basic rule of generics that prevents this is "the content of a generic type must be well-defined on the generic argument." Lets look at how this applies to the following code:
public abstract class AbstractBase
{
public abstract string MyMethod();
}
public class SomeType<T> : T
{
}
public class SomeUsage
{
void Foo()
{
// SomeType<AbstractBase> does not implement AbstractBase.MyMethod
SomeType<AbstractBase> b = new SomeType<AbstractBase>();
}
}
So we try to implement MyMethod()
:
public class SomeType<T> : T
{
public override string MyMethod()
{
return "Some return value";
}
}
public class SomeUsage
{
void Foo()
{
// SomeType<string> does not inherit a virtual method MyMethod()
SomeType<string> b = new SomeType<string>();
}
}
So lets make a requirement that T
be derived from AbstractBase
:
public abstract class DerivedAbstractBase : AbstractBase
{
public abstract string AnotherMethod();
}
public class SomeType<T> : T
where T : AbstractBase
{
public override string MyMethod()
{
return "Some return value";
}
}
public class SomeUsage
{
void Foo()
{
// SomeType<DerivedAbstractBase> does not implement DerivedAbstractBase.AnotherMethod()
SomeType<DerivedAbstractBase> b = new SomeType<DerivedAbstractBase>();
}
}
By the time you account for all the restrictions in base types, you're so constrained that deriving from a generic parameter is pointless.
Every now and then I stumble upon an implementation issue, where I deeply regret that C<T>
cannot inherit T
. Unfortunately, I have never recorded these issues and so I can describe just the most recent one - the one I have stumbled upon right now. So here it is:
Our system is extensible through metadata, which becomes available at run-time. The metadata is translated to a type dynamically generated at run-time using Reflection.Emit. Unfortunately, the dynamically generated type has to satisfy the following conditions:
IDynamicObject
(our interface), System.ComponentModel.INotifyPropertyChanged
and Csla.Core.IMobileObject
. Note, that this condition places certain constraints on the ancestor type. For instance, the ancestor type may not implement the IDynamicObject
interface, except if all the interface methods are implemented abstractly. There are other constraints, all of which must be checked.object
methods Equals
, ToString
and GetHashCode
.Currently, I had to use Reflection.Emit to emit all the IL code to satisfy these conditions. Of course, some tasks may be forwarded to statically compiled code. For instance, the override of the object.Equals(object)
method invokes DynamicObjectHelper(IDynamicObject, IDynamicObject)
which is a statically compiled C# code doing the largest bulk of the work
of comparing two dynamic objects for equality. But this is more of an exception than the rule - most of the implementation is emitted, which is a pain in the butt.
Would not it be great to be able to write a generic type, like DynamicObjectBase<T>
which will be instantiated with the ancestor type and serve as the actual base type of the dynamically generated type? As I view it, the generic type DynamicObjectBase<T>
could implement much of the dynamic type requirements in a statically compiled C# code. The dynamically emitted type would inherit it and probably, just override a few simple virtual methods.
To conclude, my compelling reason is that letting C<T>
inherit from T
would greatly simplify the task of emitting dynamic types.
I'm using GTK# 3. There's a 'Widget' class defined which is the base for all other GTK# widgets, e.g. Window, Label, Frame. Unfortunately, the framework makes it a bit complicated to change the background-color of a widget, in the sense that you need to override a method of the Widget to do it (jeez...).
So, if I wanted to have - say - a Label for which I can arbitrarily set a background-color, I should do something like this:
class BGLabel : Label
{
private Color _bgColor;
public Color BackgroundColor
{
get { return this._bgColor; }
set { this._bgColor = value; this.QueueDraw(); /* triggers OnDraw */ }
}
protected override void OnDraw(...)
{
... /* here we can use _bgColor to paint the background */
}
}
Now, if I wanted to have this nice feature for more widgets, I'd have to do the above for each of them. If "class C< T > : T" would be compilable, I could instead just do:
class C<T> : T where T : Widget
{
private Color _bgColor;
public Color BackgroundColor
{
get { return this._bgColor; }
set { this._bgColor = value; this.QueueDraw(); /* triggers OnDraw */ }
}
protected override void OnDraw(...)
{
... /* here we can use _bgColor to paint the background */
}
}
and instead of "BGxxx bgw = new BGxxx();" I could use "C< xxx > bgw = new C< xxx >();".
While I see what you're getting at, it looks like a special case of a more general problem of poor support for type construction via composition in .NET. Would something like the approach described at https://connect.microsoft.com/VisualStudio/feedback/details/526307/add-automatic-generation-of-interface-implementation-via-implementing-member be sufficient for you?
The good reason to make it possible to inherit from a type parameter is because of the following situation:
I have would like to have an abstract ViewModel class which inherits from an Entity class and has some additional properties and methods.
public abstract class ViewModel<TEntity> : TEntity, IViewModel<TEntity>
where TEntity : class, IEntity, new() {
public void SomeMethod() {
}
}
Then i could make a specific ViewModel
public class EmployeeViewModel : ViewModel<Employee> {
}
Nice ! it inherits all the fields of the entity and has the standard properties and methods of the abstract viewmodel ! ..
This sadly cannot be done now.