#1: New constraint with interface
Add a contraint to TValue
telling the compiler it has a parameterless constructor. You can do this by adding the keyword new
to the contraint of TValue
. This way you can at least construct an item.
You cannot use paramters of generic parameter types. But you can use another contraint to define some properties:
public interface IMyValue<TValue>
{
void CopyFrom(TValue original);
}
public static List<TValue> deepCopyList<TValue>(List<TValue> src)
where TValue: IMyValue<TValue>, new() // <== Setting the constraints of TValue.
{
List<TValue> arr = new List<TValue>();
for (int i = 0; i < src.Count; i++)
{
TValue value = new TValue();
value.CopyFrom(src[i]);
arr.Add(value); // No error.
}
return arr;
}
#2: Using ICloneable
There is a second solution, and it is a bit the same. Make the value responsible for cloning it self, using ICloneable
:
public static List<TValue> deepCopyList<TValue>(List<TValue> src)
where TValue: ICloneable // <== Setting the constraints of TValue.
{
List<TValue> arr = new List<TValue>();
for (int i = 0; i < src.Count; i++)
{
TValue value = (TValue)src[i].Clone();
arr.Add(value); // No error.
}
return arr;
}
#3: Using Activator
But since you want to create a deep clone, there is another way, using the Activator
. This method is NOT type safe and can produce runtime exceptions when the type does not support that constructor call:
public static List<TValue> deepCopyList<TValue>(List<TValue> src)
{
List<TValue> arr = new List<TValue>();
for (int i = 0; i < src.Count; i++)
{
TValue value = (TValue)Activator.CreateInstance(typeof(TValue), src[i]);
arr.Add(value); // Possible runtime rror.
}
return arr;
}
Above method can also be replace by using reflection and get the correct ConstructorInfo
and use this to create new items. It is the same thing what Activator
does and has the same risk.
BTW: In C# it is called 'generic', not 'template' as in C++.