C#: Generic Constructors with Arbitrary Parameters
A VERY Fast Generic Factory Pattern Implementation

C# is a wonderful language that supports many design paradigms including Object-Oriented , Generic, Functional, Imperative and even Aspect-Oriented design. The one complaint is that some language design decisions seem arbitrary or capricious. One such example is generic constructors.
You see, in C#, you cannot constrain a generic to require a new()
operator that takes any parameters whatsoever. In fact, while many other programming languages have added constraints (Rust with traits, C++ with concepts, etc.) at the method level and C# has steadfastly towed the line that such concepts (pun!) are philosophically misaligned with generics.
Case in point:
public class SomeGeneric<T>
// Note: You cannot specify any parameters in the `where` clause new() method.
where T : new() {
static T build_me()
{
return new T();
}
}
A Long History
While C# moves remarkably quickly to keep up with current trends in software design, this “rule” has been around for a very long time. In fact, Microsoft language developers have publicly debated support for this feature, as far back as 22 years ago at the time of this writing!:
To be honest, Microsoft’s team has been perceived in the past to be somewhat flippant on occasion regarding adding features:
First, “features are expensive”.
You want to know why the feature [covariance in this case] is not implemented. … the feature is not implemented because no one here ever implemented it. A necessary but insufficient requirement is that the feature’s benefits exceed its costs.
The costs are considerable. The feature is not supported natively by the runtime, it works directly against our goal to make C# versionable because it introduces yet another form of the brittle base class problem, Anders doesn’t think it is an interesting or useful feature, and if you really want it, you can make it work by writing little helper methods. (Which is exactly what the CIL version of C++ does.)
The benefits are small. High cost, small benefit features with an easy workaround get triaged away very quickly. We have far higher priorities.
I’d like to point out that the cost for this feature is not large. It’s tiny. In fact, I’ll post an implementation in this article for y’all to use.
Secondly, “It’s not generic”:
… we are not required to provide a justification for features not existing. Features have enormous costs.
However, in this specific case [expanded constraints for new()] I can certainly give you some reasons why I would push back on the feature if it came up in a design meeting as a possible feature for a future version of the language.
To start with: consider the more general feature. Constructors are methods. If you expect there to be a way to say “the type argument must have a constructor that takes an int” then why is it not also reasonable to say “the type argument must have a public method named Q that takes two integers and returns a string?”
string M<T>(T t) where T has string Q(int, int)
{
return t.Q(123, 456);
}
Does that strike you as a very generic thing to do? It seems counter to the idea of generics to have this sort of constraint. — Eric Lippert, 2012.
I very much dislike this answer. My response is a resounding, “YES!” Yes, it is generic. It’s precisely the reason so many other languages support much more powerful generics. Unfortunately, Eric made an important mistake here: assuming you know what’s best for architects and developers. Give them the tools. Let them figure out how to create with them. Don’t restrict features because they don’t align with your personal philosophy. Designing architecture or languages should be about supporting your end users in situations you haven’t yet contemplated.
The Generic Factory
To work around this issue, as Eric suggests, let’s set our objective. What feature do we want to see?
var some_base_constructor
= ConstructorFactory<SomeBase>
.CreateBuilder<int,float,string>(typeof(SomeDerived));
// Create an instance of SomeDerived using your "virtual" constructor.
var base_reference = some_base_constructor(4, 3.2f, "foo foo");
Ideally, as above, we’d like to create a factory that generically produces an object of some type for us. In the above example, some_base_constructor
is assigned a method that will build a constructor lambda expression for us that will take any parameters. In the case above, an int
, float
, and string.
Once we have a constructor cached, we can call it anytime we like!
The Approach
Earlier, I mentioned lambda expressions. C# added a feature that lets you compile code from your code. A lambda expression creates a closure. We’ll exploit that to piece together a bit of code that takes some arbitrary parameters and returns the base type of some derived type. I’ve commented the code below:
//A generic factory.
public static class ConstructorFactory<T> {
// ------------------------------------------------
// Internal class to make builder lambda functions
// ------------------------------------------------
private static class BuilderFactoryImpl<BUILD_FUNCTION> {
// Given a derived type, and some arbitrary parameters
// (defined in BUILD_FUNCTION), return a constructor.
public static BUILD_FUNCTION
buildBuilderWithArgs(Type derivedType = null) {
// If no derived type specified, use type of T.
// --------------------------------------------
derivedType = derivedType ?? typeof(T);
// Check to make sure derivedType is T.
// ------------------------------------
if (!derivedType.IsSubclassOf(typeof(T))
&& derivedType != typeof(T)) {
throw new ArgumentException("Type error.");
}
// Get the generic arguments from the functor.
// -------------------------------------------
var genericArguments =
typeof(BUILD_FUNCTION).GetGenericArguments();
// One of the arguments is the return value.
// We are interested in the parameters types.
// ------------------------------------------
var numArgs = genericArguments.Count() - 1;
// Get the parameters and forget about the return type.
// ----------------------------------------------------
var buildFunctionParams = genericArguments.Take(numArgs);
// Find the constructor with the same parameters.
// ----------------------------------------------
var ctor = derivedType
.GetConstructor(buildFunctionParams.ToArray());
// Using LINQ, create Expression parameters with the names
// and types matching the constructor.
// -------------------------------------------------------
var parameters = ctor
.GetParameters()
.Select(p => Expression
.Parameter(p.ParameterType, p.Name))
.ToArray();
// A lambda expression that creates a new instance
// of the type of derivedType using the constructor
// requested. It's compiled for performance.
// ------------------------------------------------
var e = Expression.New(ctor, parameters);
// Compile a lambda function that performs new.
// --------------------------------------------
return Expression
.Lambda<BUILD_FUNCTION>(e, parameters)
.Compile();
}
}
// ---------------------------------------
// Helper functions to create the lambdas.
// ---------------------------------------
public static Func<T>
CreateBuilder(Type derivedType = null) {
return BuilderFactoryImpl<Func<T>>
.buildBuilderWithArgs(derivedType);
}
public static Func<P1, T>
CreateBuilderWithArgs<P1>(Type derivedType = null) {
return BuilderFactoryImpl<Func<P1,T>>
.buildBuilderWithArgs(derivedType);
}
public static Func<P1, P2, T>
CreateBuilderWithArgs<P1, P2>(Type derivedType = null) {
return BuilderFactoryImpl<Func<P1, P2, T>>
.buildBuilderWithArgs(derivedType);
}
public static Func<P1, P2, P3, T>
CreateBuilderWithArgs<P1, P2, P3>(Type derivedType = null) {
return BuilderFactoryImpl<Func<P1, P2, P3, T>>
.buildBuilderWithArgs(derivedType);
}
public static Func<P1, P2, P3, P4, T>
CreateBuilderWithArgs<P1, P2, P3, P4>(Type derivedType = null) {
return BuilderFactoryImpl<Func<P1, P2, P3, P4, T>>
.buildBuilderWithArgs(derivedType);
}
// You see the pattern here? You can add more parameters as you like...
}
Let’s define some base and derived types to demonstrate how this is used.
namespace GenericConstructorTest;
// Some base class.
public abstract class SomeBase
{
// An abstract method.
public abstract void Print();
}
// A derived class.
public class SomeDerived : SomeBase
{
private readonly int i;
private readonly float f;
private readonly string s;
// The constructor we're interested in:
public SomeDerived(int i, float f, string s)
{
this.i = i;
this.f = f;
this.s = s;
}
// Overriding the abstract method.
public override void Print()
{
Console.WriteLine($"i: {i}, f: {f}, s: \"{s}\"");
}
}
As I mentioned before at the top of the article, we can instantiate our factory and opaquely construct our object of type SomeDerived.
Now, folks might ask, “If you know the type SomeDerived
, why not just call the constructor directly? The answer is that the type can be ascertained from the reflection system, given the string name of the class, either in a configuration file, or passed in dynamically.
Creating an instance of your derived type using a generic factory:
// 1.)
var some_base_constructor
= ConstructorFactory<SomeBase>
.CreateBuilderWithArgs<int,float,string>(typeof(SomeDerived));
// 2.)
// Create an instance of SomeDerived using your "virtual" constructor.
var base_reference = some_base_constructor(4, 3.2f, "foo foo");
In the first line, the constructor is created by the factory. We tell the ConstructorFactory
what base type we’d like to work with ( SomeBase
in this case ) and the type we actually want the factory to build ( SomeDerived
). We specify that we want a constructor that takes an int
, float
, and string
.
In the second line, we call the constructor and build an instance of SomeDerived
, returning a reference to SomeBase
.
Caching
It’s important to note that creating the generic, virtual constructor takes a lot of time. Orders of magnitude more time than the constructor. For this reason, you should create the constructor and then cache it away somewhere for later use. Don’t create a factory every time you need to create an instance!
Performance
Well, this is the important part. Why bother doing any of this when .net provides the Activator
class that will do all this for you?
The answer is that Activator
is painfully slow. Unbelievably slow. I’ve been programming with C# since it was J++. I have never used Activator
in production code. For completeness, this is how you would use Activator
to accomplish the same thing:
var base_reference =
Activator.CreateInstance(
typeof(SomeDerived),
new object[] { 4, 3.2f, "foo foo" }
);
Seems simple enough. Sadly, It takes 55x longer than the generic solution posted above!
To analyze this generic constructor performance, I also measured it against the raw new method. Surprise! It performs identically to the native constructor! To be honest, I did not expect this result. I tested this same approach many years ago on an old 486, 50MHz (dual processor!) machine and the generic constuctor performed slightly worse than native and about 50x better than Activator
.
Results (Some very large number of iterations.)
- Native Constructor……..1ms
- Generic Constructor……1ms
- Activator…………………..55ms
All tests were performed on a Lambda Vector workstation using a 4.3Ghz AMD Ryzen™ Threadripper 3990x x 128 with 256GiB of RAM.
The Code
The code and timing test can be found on github here:
Questions? Comments?
I hope you’ve enjoyed this article. Please do leave questions and comments!