Ich versuche herauszufinden, wie man Vorlagen in C# verwendet. Ich habe das geschrieben:
public static List<TValue> deepCopyList<TValue>(List<TValue> src)
{
List<TValue> arr = new List<TValue>();
for (int i = 0; i < src.Count; i++)
{
arr.Add(new TValue(src[i])); //Error on this line
}
return arr;
}
Aber ich bekomme einen Fehler:
Fehler CS0304: Es kann keine Instanz des Variablentyps „TValue" erstellt werden, da er nicht über die new()-Einschränkung verfügt
Lösung des Problems
#1: Neue Einschränkung mit Schnittstelle
Fügen Sie eine Einschränkung hinzu, TValue
um dem Compiler mitzuteilen, dass er einen parameterlosen Konstruktor hat. Sie können dies tun, indem Sie das Schlüsselwort new
zur Einschränkung von hinzufügen TValue
. Auf diese Weise können Sie zumindest einen Gegenstand konstruieren.
Sie können keine Parameter generischer Parametertypen verwenden. Sie können jedoch eine andere Einschränkung verwenden, um einige Eigenschaften zu definieren:
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: Verwendung von ICloneable
Es gibt eine zweite Lösung, und es ist ein bisschen die gleiche. Machen Sie den Wert für das Klonen selbst verantwortlich, indem Sie Folgendes verwenden 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: Verwendung von Aktivator
Da Sie jedoch einen tiefen Klon erstellen möchten, gibt es einen anderen Weg, indem Sie die Activator
. Diese Methode ist NICHT typsicher und kann Laufzeitausnahmen erzeugen, wenn der Typ diesen Konstruktoraufruf nicht unterstützt:
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;
}
Die obige Methode kann auch durch die Verwendung von Reflektion ersetzt werden und die richtige erhalten ConstructorInfo
und diese verwenden, um neue Elemente zu erstellen. Es ist dasselbe, was dasselbe Activator
tut und dasselbe Risiko hat.
BTW: In C# heißt es 'generic', nicht 'template' wie in C++.
Keine Kommentare:
Kommentar veröffentlichen