Can you please explain to me what where T : class, new()
means in the following line of code?
void Add<T>(T item) where T : class, new();
That is a constraint on the generic parameter T
. It must be a class
(reference type) and must have a public parameter-less default constructor.
That means T
can't be an int
, float
, double
, DateTime
or any other struct
(value type).
It could be a string
, or any other custom reference type, as long as it has a default or parameter-less constructor.
Those are generic type constraints. In your case there are two of them:
where T : class
Means that the type T
must be a reference type (not a value type).
where T : new()
Means that the type T
must have a parameter-less constructor. Having this constraint will allow you to do something like T field = new T();
in your code which you wouldn't be able to do otherwise.
You then combine the two using a comma to get:
where T : class, new()
where T : struct
The type argument must be a value type. Any value type except Nullable can be specified. See Using Nullable Types (C# Programming Guide) for more information.
where T : class
The type argument must be a reference type, including any class, interface, delegate, or array type. (See note below.)
where T : new() The type argument must have a public parameterless constructor. When used in conjunction with other constraints, the new() constraint must be specified last.
where T : [base class name]
The type argument must be or derive from the specified base class.
where T : [interface name]
The type argument must be or implement the specified interface. Multiple interface constraints can be specified. The constraining interface can also be generic.
where T : U
The type argument supplied for T must be or derive from the argument supplied for U. This is called a naked type constraint.
(Original Source: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters)
class
& new
are 2 constraints on the generic type parameter T
.
Respectively they ensure:
class
The type argument must be a reference type; this applies also to any class, interface, delegate, or array type.
new
The type argument must have a public parameterless constructor. When used together with other constraints, the new() constraint must be specified last.
Their combination means that the type T
must be a Reference Type (can't be a Value Type), and must have a parameterless constructor.
Example:
struct MyStruct { } // structs are value types
class MyClass1 { } // no constructors defined, so the class implicitly has a parameterless one
class MyClass2 // parameterless constructor explicitly defined
{
public MyClass2() { }
}
class MyClass3 // only non-parameterless constructor defined
{
public MyClass3(object parameter) { }
}
class MyClass4 // both parameterless & non-parameterless constructors defined
{
public MyClass4() { }
public MyClass4(object parameter) { }
}
interface INewable<T>
where T : new()
{
}
interface INewableReference<T>
where T : class, new()
{
}
class Checks
{
INewable<int> cn1; // ALLOWED: has parameterless ctor
INewable<string> n2; // NOT ALLOWED: no parameterless ctor
INewable<MyStruct> n3; // ALLOWED: has parameterless ctor
INewable<MyClass1> n4; // ALLOWED: has parameterless ctor
INewable<MyClass2> n5; // ALLOWED: has parameterless ctor
INewable<MyClass3> n6; // NOT ALLOWED: no parameterless ctor
INewable<MyClass4> n7; // ALLOWED: has parameterless ctor
INewableReference<int> nr1; // NOT ALLOWED: not a reference type
INewableReference<string> nr2; // NOT ALLOWED: no parameterless ctor
INewableReference<MyStruct> nr3; // NOT ALLOWED: not a reference type
INewableReference<MyClass1> nr4; // ALLOWED: has parameterless ctor
INewableReference<MyClass2> nr5; // ALLOWED: has parameterless ctor
INewableReference<MyClass3> nr6; // NOT ALLOWED: no parameterless ctor
INewableReference<MyClass4> nr7; // ALLOWED: has parameterless ctor
}
new(): Specifying the new() constraint means type T must use a parameterless constructor, so an object can be instantiated from it - see Default constructors.
class: Means T must be a reference type so it can't be an int, float, double, DateTime or other struct (value type).
public void MakeCars()
{
//This won't compile as researchEngine doesn't have a public constructor and so can't be instantiated.
CarFactory<ResearchEngine> researchLine = new CarFactory<ResearchEngine>();
var researchEngine = researchLine.MakeEngine();
//Can instantiate new object of class with default public constructor
CarFactory<ProductionEngine> productionLine = new CarFactory<ProductionEngine>();
var productionEngine = productionLine.MakeEngine();
}
public class ProductionEngine { }
public class ResearchEngine
{
private ResearchEngine() { }
}
public class CarFactory<TEngine> where TEngine : class, new()
{
public TEngine MakeEngine()
{
return new TEngine();
}
}
That means that type T
must be a class and have a constructor that does not take any arguments.
For example, you must be able to do this:
T t = new T();
The new() Constraint lets the compiler know that any type argument supplied must have an accessible parameterless--or default-- constructor
So it should be, T
must be a class, and have an accessible parameterless--or default constructor.
What comes after the "Where" is a constraint on the generic type T you declared, so:
class means that the T should be a class and not a value type or a struct.
new() indicates that the T class should have a public parameter-free default constructor defined.
It's called a 'constraint' on the generic parameter T. It means that T must be a reference type (a class) and that it must have a public default constructor.
This is part of the Generics mechanism, where the where keyword add constraints to what types must implement in order to be used as type parameters.
when using the class in constraints it's mean you can only use Reference type, another thing to add is when to use the constraint new(), it's must be the last thing you write in the Constraints terms.
Success story sharing
new()
precisely specifies "must have a public parameterless constructor"