Reputation: 67345
I'm trying to create a generics method. I want the caller to be able to define two different types.
private TableRow AddRowHelper<TROW, TCELL>(params string[] content) where TROW : TableRow where TCELL : TableCell
{
TableRow row = new TROW();
foreach (var text in content)
{
TableCell cell = new TCELL();
cell.Text = text;
row.Cells.Add(cell);
}
productsTable.Rows.Add(row);
return row;
}
The code above gives me an error.
Error 4 Cannot create an instance of the variable type 'TROW' because it does not have the new() constraint"
Is it possible to specify both a new
and base-type constraint? And why do I need a new constraint when I have specified that the type must derive from TableRow
, which always has a new
operator.
Upvotes: 2
Views: 103
Reputation: 82337
It is possible to specify both a new and base-type constraint. Doing that would make your method signature look like this
public TableRow AddRowHelper<TROW, TCELL>(params string[] content)
where TROW : TableRow, new() where TCELL : TableCell, new()
{
Any time you are instantiating based on a generic type, you must use the new
constraint to restrict the generic types to those which have a public parameterless constructor. Further, a method cannot provide arguments when creating an instance of a variable type.
You need a new
constraint even though you have specified that the type must derive from TableRow ( which always has a new operator ) because the derived type may not have a public parameterless constructor, and that is the one which would be called.
Consider this:
public class A : TableRow
{
private A(){}
}
And consider it being used
AddRowHelper<A,TableCell>(args);
This will cause a compilation error,
'A' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TROW' in the generic type or method 'AddRowHelper(params string[])'
Upvotes: 2
Reputation: 157098
The default, parameterless constructor can be hidden by a deriving class. Hence, the new()
constraint can't be inherited from the base class.
Sample:
public class TableRow
{ } // implements a default, parameterless constructor
public class DeivedRow : TableRow
{
public DerivedRow(string s)
{ } // no parameterless constructor
}
Upvotes: 3
Reputation: 101711
Why do I need a new constraint when I have specified that the type must derive from TableRow, which always has a new operator.
Well TROW
might be a type that inherits from TableRow
and doesn't have a default public constructor.That's why you need to add a new()
constraint.
Upvotes: 5