Von einer generischen Basisklasse erben, eine Einschränkung anwenden und eine Schnittstelle in C # implementieren

116

Dies ist eine Syntaxfrage. Ich habe eine generische Klasse, die von einer generischen Basisklasse erbt und eine Einschränkung auf einen der Typparameter anwendet. Ich möchte auch, dass die abgeleitete Klasse eine Schnittstelle implementiert. Für mein Leben kann ich anscheinend nicht die richtige Syntax herausfinden.

Das habe ich:

DerivedFoo<T1,T2> : ParentFoo<T1, T2> where T2 : IBar { ... }

Das erste, was mir in den Sinn kam, war Folgendes:

DerivedFoo<T1,T2> : ParentFoo<T1, T2> where T2 : IBar, IFoo { ... }

Dies ist jedoch falsch, da T2 sowohl IBar als auch IFoo implementieren muss und nicht DerivedFoo, um IFoo zu implementieren.

Ich habe ein bisschen googeln versucht, Doppelpunkte, Semikolons usw. verwendet, aber ich bin kurz aufgetaucht. Ich bin sicher, die Antwort ist einfach.

Dan Rigby
quelle
Ich konnte @ Adams Antwort nicht verstehen, als ich einmal hinschaute, aber nach 2 Minuten konnte ich bekommen, was es ist, danke für die Antwort. Abgeleitete Klasse hat mehr als eine Implementierung. Dies ist möglicherweise der Punkt. Wie auch immer, ich möchte seine Notation für andere zeigen. "Klasse DerivedClass <Typ>: ParentClass wobei Typ: IType". Zwischen der zuletzt implementierten Klasse und der where-Klausel sollte sich nichts befinden.
Nurisezgin

Antworten:

172

Sie fügen die gesamte Signatur Ihrer Klasse ein, bevor Sie allgemeine Einschränkungen definieren.

class DerivedFoo<T1, T2> : ParentFoo<T1, T2>, IFoo where T2 : IBar
{
    ...
}
Adam Robinson
quelle
5
Für andere habe ich dies verinnerlicht, da eine Klasse nur eine where-Klausel erhält und diese am Ende für alle allgemeinen Typeinschränkungen gilt.
Andy V
@Visser Es ist erlaubt, mehrere where-Klauseln zu haben, Klasse Test <T1, T2> wobei T1: Interface1 wobei T2: Interface2
bwing
@Visser ja, was bwing gesagt hat, auch jede where-Klausel kann mehrere Einschränkungen haben ... also ist die Syntax aus dem ursprünglichen Beitrag korrekt, es bedeutet nur etwas anderes, was die Operation wollte. where T2 : IBar, IFoo bedeutet nur, dass T2beide Schnittstellen implementiert werden müssen, anstatt zu DerivedFoo<T1,T2> implementierenIFoo
v01pe
18

Meine Empfehlung: Wenn Sie eine Frage zur Syntax der C # -Sprache haben, lesen Sie die Spezifikation. Deshalb veröffentlichen wir es. Sie sollten Abschnitt 10.1 lesen.

Um Ihre spezifische Frage zu beantworten, lautet die Reihenfolge der Dinge in einer Klassendeklaration:

  • Attribute in eckigen Klammern
  • Modifikatoren ("öffentlich", "statisch" usw.)
  • "teilweise"
  • "Klasse"
  • der Klassenname
  • Eine durch Kommas getrennte Liste von Typparameterdeklarationen in spitzen Klammern
  • Ein Doppelpunkt folgte einer durch Kommas getrennten Liste von Basistypen (Basisklasse und implementierte Schnittstellen, Basisklasse muss zuerst gehen, wenn es eine gibt)
  • Geben Sie Parametereinschränkungen ein
  • der Körper der Klasse, umgeben von Zahnspangen
  • ein Semikolon

Alles in dieser Liste ist optional, außer "Klasse", dem Namen und dem Textkörper, aber alles muss in dieser Reihenfolge erscheinen, wenn es erscheint.

Eric Lippert
quelle
94
Eric, obwohl ich Sie als Fachmann sehr respektiere und Ihr Feedback schätze, kann ich nicht anders, als frustriert zu sein über das, was als aggressive Antwort herauskommt. Sie kritisieren mich dafür, dass ich auf einer Programmier-Q & A-Site eine Frage zum Auffinden, Herunterladen und Durchsuchen eines hochtechnischen Word-Dokuments mit 503 Seiten gestellt habe, das in einem Link in MSDN vergraben ist. Das ist ziemlich rau. Dies war die effizienteste Nutzung meiner Zeit und hat den zusätzlichen Vorteil, dass es später jemand anderem helfen kann. Der Link zur C # Lang- Spezifikation
Dan Rigby
17
Es war keine Kritik beabsichtigt. In der Reintextkommunikation gibt es eine allgegenwärtige Tendenz, die einfache Tatsachenaussagen brüsk und aggressiv klingen lässt. Ich versuche, gemeinnützig zu lesen, wenn mir eine Liste hilfreicher Fakten vorgelegt wird, und empfehle Ihnen, dies ebenfalls zu tun. Ich stehe zu meiner Empfehlung; Wenn Sie Fragen zur Syntax haben, beantwortet die Spezifikation diese endgültig und beginnt mit einem hilfreichen Inhaltsverzeichnis zum Auffinden von Definitionen bestimmter Syntaxen.
Eric Lippert
3
Dan, das Finden der C # -Spezifikation ist so einfach wie das Eingeben von "C # -Spezifikation" in Google und das Klicken auf die Schaltfläche "Ich habe Glück". Und wenn Sie ein professioneller C # -Entwickler sind, sollten Sie bereits C # -Spezifikationen im PDF-Format auf Ihrem Computer haben. Ich will dich auch nicht kritisieren. Ich war es nicht gewohnt, Spezifikationen früher zu lesen, aber ich habe dank Jon, Eric und Pavel, die bei Fragen immer C # -Spezifikationen zitieren, angefangen, sie zu lesen. Ich fand, dass C # -Spezifikation, obwohl es manchmal schwer zu lesen sein kann, eine großartige Möglichkeit ist, etwas über die Sprache zu lernen.
SolutionYogi
@ Eric Lippert: Fair genug. Danke für Ihre Antwort. Als konstruktiver Vorschlag wäre es hilfreich, wenn Microsoft den Inhalt der Spezifikation direkt in MSDN integrieren und ihn als separaten Download bereitstellen würde. Die Visual Studio .Net MSDN-Version verfügt über eine integrierte Version der Spezifikation, jedoch nicht über spätere Versionen. Ich habe darüber nachgedacht, Anders Hejlbergs Buch zu kaufen, aber mit .Net 4.0 um die Ecke zögere ich gerade noch. amazon.com/C-Programming-Language-3rd/dp/0321562992 Danke.
Dan Rigby
2
C ++ erfordert, dass eine Klassendeklaration mit einem Semikolon endet. Viele C # -Entwickler haben einen C ++ - Hintergrund. manchmal setzen ihre Finger das Semikolon ein, ohne dass sich ihr Gehirn einmischt. :-) Es gibt eine Reihe von Konstrukten in C #, die ein optionales Semi verwenden, für das C ++ eines benötigt. Es ist so ziemlich nur eine subtile Annehmlichkeit. Ich nehme an, Sie können damit auch subtil aufrufen, wenn eine Typdeklaration endet, oder beispielsweise eine Methodenkörperdeklaration.
Eric Lippert
8
public interface IFoo {}
public interface IBar {}

public class ParentFoo<T,T1> { }
public class DerivedFoo<T, T1> : ParentFoo<T, T1>, IFoo where T1 : IBar { }
Stan R.
quelle
2
public class KeyAndValue<T>
{
    public string Key { get; set; }
    public virtual T Value { get; set; }
}

public class KeyAndValue : KeyAndValue<string>
{
    public override string Value { get; set; }
}

Dies ist eine Erweiterung der vorhandenen Antworten. Der Standardwert ist, stringwenn Sie keinen Typ angeben . Ich habe keine Schnittstelle implementiert, aber das sollte nichts anderes als gewöhnlich erfordern.

user875234
quelle