Als ich dies las , erfuhr ich, dass es möglich war, einer Methode zu erlauben, Parameter mehrerer Typen zu akzeptieren, indem sie zu einer generischen Methode gemacht wurde. Im Beispiel wird der folgende Code mit einer Typbeschränkung verwendet, um sicherzustellen, dass "U" ein ist IEnumerable<T>
.
public T DoSomething<U, T>(U arg) where U : IEnumerable<T>
{
return arg.First();
}
Ich habe mehr Code gefunden, mit dem mehrere Typeinschränkungen hinzugefügt werden können, z.
public void test<T>(string a, T arg) where T: ParentClass, ChildClass
{
//do something
}
Dieser Code scheint jedoch zu erzwingen, dass arg
dies sowohl eine Art von ParentClass
als auch sein muss ChildClass
. Was ich tun möchte, ist zu sagen, dass arg eine Art ParentClass
oder ChildClass
auf folgende Weise sein könnte:
public void test<T>(string a, T arg) where T: string OR Exception
{
//do something
}
Ihre Hilfe wird wie immer geschätzt!
c#
asp.net-mvc-3
types
Mansfield
quelle
quelle
where T : string
, ebensostring
wie eine versiegelte Klasse. Das einzig Nützliche, was Sie tun können, ist das Definieren von Überladungen fürstring
undT : Exception
, wie von @ Botz3000 in seiner Antwort unten erläutert.arg
die durch definiert sind.object
Warum also nicht einfach Generika aus dem Bild entfernen und den Typ festlegenarg
object
? Was gewinnen Sie?Antworten:
Das ist nicht möglich. Sie können jedoch Überladungen für bestimmte Typen definieren:
Wenn diese Teil einer generischen Klasse sind, werden sie der generischen Version der Methode vorgezogen.
quelle
or
Beziehung Dinge viel zu allgemein macht, um nützlich zu sein. Sie würden haben Reflexion Figur zu tun, was zu tun und alle. (YUCK!).Die Antwort von Botz ist zu 100% richtig. Hier eine kurze Erklärung:
Wenn Sie eine Methode schreiben (generisch oder nicht) und die Typen der Parameter deklarieren, die die Methode verwendet, definieren Sie einen Vertrag:
Wenn Sie versuchen, mehr als einen Typ gleichzeitig anzugeben (indem Sie ein oder haben) oder versuchen, einen Wert zurückzugeben, der mehr als einen Typ sein kann, wird der Vertrag unscharf:
Das Problem ist, dass Sie beim Einstieg in die Methode keine Ahnung haben, ob sie Ihnen eine
IJumpRope
oder eine gegeben habenPiFactory
. Wenn Sie die Methode verwenden (vorausgesetzt, Sie haben sie auf magische Weise kompiliert), sind Sie sich nicht sicher, ob Sie eineFisher
oder eine habenAbstractConcreteMixer
. Grundsätzlich macht es das Ganze viel verwirrender.Die Lösung für Ihr Problem ist eine von zwei Möglichkeiten:
Definieren Sie mehr als eine Methode, die jede mögliche Transformation, jedes mögliche Verhalten oder was auch immer definiert. Das ist Botz 'Antwort. In der Programmierwelt wird dies als Überladen der Methode bezeichnet.
Definieren Sie eine Basisklasse oder Schnittstelle, die alle für die Methode erforderlichen Aufgaben ausführen kann, und lassen Sie eine Methode genau diesen Typ verwenden. Dies kann das Einschließen eines
string
undException
in eine kleine Klasse beinhalten, um zu definieren, wie Sie sie der Implementierung zuordnen möchten, aber dann ist alles sehr klar und leicht zu lesen. Ich könnte in vier Jahren kommen und Ihren Code lesen und leicht verstehen, was los ist.Welche Sie wählen, hängt davon ab, wie kompliziert Auswahl 1 und 2 wäre und wie erweiterbar sie sein muss.
Für Ihre spezielle Situation stelle ich mir vor, Sie ziehen nur eine Nachricht oder etwas aus der Ausnahme heraus:
Jetzt brauchen Sie nur noch Methoden, die a
string
und anException
in eine IHasMessage umwandeln. Sehr leicht.quelle
Wenn ChildClass bedeutet, dass es von ParentClass abgeleitet ist, können Sie einfach Folgendes schreiben, um sowohl ParentClass als auch ChildClass zu akzeptieren.
Wenn Sie andererseits zwei verschiedene Typen ohne Vererbungsbeziehung verwenden möchten, sollten Sie die Typen berücksichtigen, die dieselbe Schnittstelle implementieren.
dann können Sie Ihre generische Funktion schreiben als;
quelle
So alt diese Frage auch ist, ich bekomme immer noch zufällige Upvotes zu meiner obigen Erklärung. Die Erklärung ist immer noch vollkommen in Ordnung, aber ich werde ein zweites Mal mit einem Typ antworten, der mir als Ersatz für Unionstypen dient (die stark typisierte Antwort auf die Frage, die von C # nicht direkt unterstützt wird) ).
Die obige Klasse stellt einen Typ dar, der entweder TP oder TA sein kann. Sie können es als solches verwenden (die Typen beziehen sich auf meine ursprüngliche Antwort):
Wichtige Notizen:
IsPrimary
zuerst überprüfen .IsNeither
IsPrimary
oder überprüfenIsAlternate
.Primary
und auf den Wert zugreifenAlternate
Either
beliebigen Ort übergeben können, an dem einer erwartet wird. Wenn Sie tun , ein PassEither
, wo einTA
oderTP
erwartet wird, aber derEither
enthält die falsche Art von Wert finden Sie einen Laufzeitfehler erhalten.Ich verwende dies normalerweise, wenn eine Methode entweder ein Ergebnis oder einen Fehler zurückgeben soll. Es bereinigt wirklich diesen Stilcode. Ich benutze dies auch sehr gelegentlich ( selten ) als Ersatz für Methodenüberladungen. Realistisch gesehen ist dies ein sehr schlechter Ersatz für eine solche Überlastung.
quelle