C# Feature Request: Type Member Level Generic Constraints
The Basic Need
Take the following code:
public abstract class Base
{
protected Base(int something)
{
// ...
}
}
public class Derived : Base
{
public Derived(int something)
: base(something)
{
// ...
}
}
public class Derived2 : Base
{
public Derived2(int something)
: base(something)
{
// ...
}
}
Where Base is not my code, forcing me to create non-empty constructors so I could call the base constructor.
Now, I would like to accept types deriving from Base as a generic parameter and instantiate them in my type. This is how my could will have to look:
public class Generic<TBase> where TBase : Base
{
public void Method()
{
Base something = (Base)Activator.CreateInstance(typeof(TBase), 0);
}
}
Argh! I have to use Activator.CreateInstance, which is both slow and untyped. I can't move the initialization from the constructor to another method, since it's not up to me. What a fall from grace. What I need here is something similar to
duck typing.
So here's a syntax I'm suggesting for the next version of C#:
public class Generic<TBase> where TBase : Base, new(int)
{
public void Method()
{
Base something = new TBase(0);
}
}
Now there's no messy untyped stuff in my code, plus I get Generics' performance boost.
The Next Level
Why stop at constructors? Let's change our code a bit:
public class Derived : Base
{
public Derived(int something)
: base(something)
{
// ...
}
public int Foo()
{
}
}
Say I have another class, DerivedEx, which exists in an assembly I have no control over, derives from Base and has the same signature method Foo.
Now I want to limit my types to only those that have this Foo method. I can put an interface on Derived, but since I can't control DerivedEx, I can't place an interface on it.
Why not use what we've already started then:
public class Generic<TBase> where TBase : Base, has Func<int> Foo, new(int)
{
public void Method()
{
TBase something = new TBase(0);
int value = something.Foo();
}
}
Notice that we are, in effect, staying completely typed: The compiler is certain that any type argument supplied to Generic has an integer accepting constructor and a function named Foo which adheres to the Func<int> delegate. On the other side, the compiler can check the supplied type argument for these conditions.
I've taken great care to make sure the syntax I propose does not conflict with C# 3.0's, but I wouldn't mind it being changed - just that it gets implemented. ;)