Hydrargyrum Hydrargyrum - 2 months ago 8
C# Question

Why is Activator.CreateInstance<T>() allowed without the new() generic type constraint?

In the sample code shown below, the "CompileError" method won't compile, because it requires the

where T : new()
constraint as shown in the
CreateWithNew()
method. However, the
CreateWithActivator<T>()
method compiles just fine without a constraint.

public class GenericTests
{
public T CompileError<T>() // compile error CS0304
{
return new T();
}

public T CreateWithNew<T>() where T : new() // builds ok
{
return new T();
}

public T CreateWithActivator<T>() // builds ok
{
return Activator.CreateInstance<T>();
}
}


Why is this?

According to http://stackoverflow.com/a/1649108/531971, which references MSDN documentation, and this question, the
new T()
expression in generics is actually implemented using
Activator.CreateInstance<T>()
. So I don't understand why calling
new T()
requires that the generic type be constrained in a way that can be omitted when using
Activator.CreateInstance<T>()
.

Or, to put the question the other way around: what's the point of the
where T : new()
constraint, if it's easy to create instances of
T
in a generic method without the constraint, by directly using the exact same underlying infrastructure?

Answer

There is a conceptual difference between Activator and T():

  • Activator.CreateInstance<T> — I want to create a new instance of T using its default constructor — And throw an Exception if it doesn't have one (Since something very wrong has happened and I want to handle it/throw it myself).

  • T() — I Want to call the empty constructor of T, supposedly like a standard constructor call.

You don't want a "standard" constructor call to fail because "No such constructor was found", therefore, the compiler wants you to constraint that there is one.

More than that; You should prefer Compile time errors over Exceptions where possible.

The fact that T() is implemented internally using reflection irrelevant for the average case of "I just want a default instance of T" (of course that the internal implementation is important if you care about performance/etc...).

Comments