Wie lassen sich Dateien, die gleichnamige generische Klassen enthalten, am besten strukturieren und benennen?

14

In meinem aktuellen Projekt bin ich auf die Anforderung gestoßen, generische Klassen mit demselben Namen, aber unterschiedlicher Anzahl von generischen Parametern zu erstellen. Beispielsweise:

MyClass<T1>
MyClass<T1, T2>
MyClass<T1, T2, T3>

Da ich alle im selben Namespace haben möchte, bin ich nicht sicher, wie ich meine Klassen und Dateien strukturieren und benennen soll.

Wenn wir der Idee folgen, dass wir Klassen auf eine pro Datei beschränken sollten und dass sich Dateien in einer Ordnerstruktur befinden sollten, die die Namespace-Hierarchie darstellt, und dass der Name der Datei mit dem Namen der Klasse übereinstimmen sollte, wie gehe ich mit dieser Situation um ?

Was ich hier wirklich frage, ist, wie soll ich die Datei benennen, die enthält MyClass<T1>, und wie soll ich die Datei benennen, die enthält MyClass<T1, T2>? Ich frage nicht, wie die Namen der Typparameter sein sollten.

Stephen
quelle
Nennen Sie uns einige konkrete Beispiele, die das Problem genauer beschreiben. Die Beispiele, die Sie angegeben haben, sind zu ... allgemein gehalten. Was meinen Sie mit "Strukturieren und Benennen meiner Klassen und Dateien"?
Robert Harvey
Microsoft tut dies selbst, indem es lediglich eine Zahl an den Typparameter anfügt. Siehe Tuple-Dokumente: msdn.microsoft.com/en-us/library/…
Pete
@Pete: Das gilt eigentlich nur für Tuple. Microsoft verwendet auch die TKey, TValueKonvention. Func hat einen TResultTypparameter. Obwohl ich damit einverstanden , dass Sie verwenden können T1, T2usw. für eine variable Anzahl von Eingabeparametern , die wie keine sonst spezifische Anwendungen haben TKeyund TValue.
Robert Harvey
@RobertHarvey Nun ja, aber nur im Zusammenhang mit einer tatsächlichen Schlüssel- / Wertsammlung wie einem Wörterbuch. Für alles, was aus einer variablen Anzahl von Typen besteht, wird eine Zahl angehängt. Hier ist ein weiteres Beispiel: msdn.microsoft.com/en-us/library/dd402872(v=vs.110).aspx
Pete
1
Nun, Ihre Änderungen haben einige der Kommentare überflüssig gemacht. :) Warum können Sie die Klassen nicht einfach in derselben physischen Datei belassen? Wenn sie so unterschiedlich sind, dass Sie sie in separaten Dateien aufbewahren müssen, können Sie uns dann sagen, was sie unterscheidet?
Pete

Antworten:

14
MyGenericClass`1.cs
MyGenericClass`2.cs
MyGenericClass`3.cs

Und so weiter, wobei die Zahl nach dem Backtick die Anzahl der generischen Typparameter ist. Diese Konvention wird von Microsoft verwendet.

Alternativ können Sie auch so etwas verwenden

MyGenericCollectionClass[TKey, TValue].cs

Dabei bleibt nicht nur die Anzahl der generischen Typparameter erhalten, sondern auch deren spezifische Namen. Zugegeben, es bewahrt nicht die spitzen Klammern, aber wir können nicht alles im Leben haben, was wir wollen, oder?

Robert Harvey
quelle
1
Der Compiler verwirrt intern den Namen generischer Typen, fügt ein Backtick und die Anzahl generischer Parameter hinzu, da .NET nicht mehrere Typen mit demselben Namen mit einer unterschiedlichen Anzahl generischer Parameter zulässt, C # jedoch. Daher entspricht die Dateinamenskonvention dem, was der Compiler tut.
CodesInChaos
1
Ich wollte dir das Gegenteil beweisen, aber eigentlich hast du recht : github.com/dotnet/corefx/tree/master/src/… Diese Konvention gefällt mir nicht.
Den
1
@Den, es scheint, dass sie jetzt von dieser Konvention bedauert haben. Vielleicht bedeutete es ein Problem? github.com/dotnet/corefx/commit/…
Sam
@Sam Hoffentlich kein Kommunikationsproblem zwischen Microsoft-Teams. Weil es sonst niemand tut. Meiner Meinung nach liegt es auch beim Compiler-Team, nicht beim Bibliotheksteam.
Den
Ich hätte nicht die Kugeln für die Verwendung von "` "in einem Dateinamen.
Cristian E.
4

Im Fall von Tupleund Action, die Pete erwähnt hat, verwendet Microsoft selbst eine einzige Datei - siehe Tuple.cs und Action.cs .

Ich denke, es hängt zum Teil davon ab, ob die Funktionalität für alle Klassen grundsätzlich gleich ist oder nicht. Ich persönlich mag es nicht, Klassen in einer einzelnen Datei zusammenzufassen, aber dies könnte eine Ausnahme sein. In dem Quellcode, in dem ich arbeite, habe ich eine automatisch generierte NamedTupleKlasse (unter Verwendung von T4) hinzugefügt, die genauso funktioniert wie Tuple, aber einen String-Namen als erstes Argument in den Konstruktor einfügt.

Um Ihre Frage zu beantworten, wenn Sie keine einzige Datei verwenden möchten MyClass<T1>, verwenden Sie möglicherweise MyClass_1.cs für , MyClass_2.cs für MyClass<T1, T2>usw.

Keine der beiden Optionen ist jedoch ideal, weshalb ich das Argument "Microsoft macht es so, also ..." vorschlagen möchte.

Wai Ha Lee
quelle
2
Tupleund Actionsind alle Delegierten; Sie haben keinen Implementierungscode, daher wäre es irgendwie sinnlos, alle Variationen in separate Dateien zu packen. Beweist nur, dass jede Regel eine Ausnahme hat.
Robert Harvey
Ja, im Allgemeinen gilt es als in Ordnung, mehrere öffentliche Delegierte in dieselbe Datei zu kopieren (sofern sie verwandt sind).
Stephen
1
@RobertHarvey Tupleist kein Delegierter, aber jede Implementierung ist trotzdem kurz.
Arturo Torres Sánchez
@ ArturoTorresSánchez: Richtig, ich habe darüber nachgedacht Func.
Robert Harvey
0

Hast du dich gefragt, ob die Klassen wirklich die gleiche Absicht haben? Wenn eine Klasse generischer als die andere ist, handelt es sich um eine GenericClass , eine MoreGenericClass und eine MostGenericClass . Stellen Sie sich vor, jeder Typparameter einer Klasse fügt der Klasse eine neue Dimension hinzu. Daher kann es hilfreich sein, zu fragen, um welche Dimension es sich handelt.

Nehmen wir dieses Beispiel:

  • Container<Thing>
  • MetricContainer<Thing, Metric>
  • MetricTransportableContainer<Thing, Metric, Transport>

Mir ist bewusst, dass es nicht das beste Beispiel ist, aber es ist sehr aussagekräftig, drei Dimensionen zu zeigen:

  • innere Dimension, was es laden kann
  • metrisch Dimension, mit welcher Metrik es geladen werden kann, nur nach Anzahl der Dinge oder nach Quadratmaß oder nach Hubraum oder nach Gewicht
  • äußere Dimension, wo es geladen werden kann.

So können Sie den Transport von Autos modellieren:

Container<Cars>
MetricContainer<Cars, CountMetric>
MetricTransportableContainer<Cars, CountMetric, Ship>

Transport von Flüssigkeiten:

Container<Fluid>
MetricContainer<Fluid, Volume>
MetricTransportableContainer<Fluid, Volume, Shelf>

Transport von Energie:

Container<Energy>
MetricContainer<Energy, ElectricPower>
MetricTransportableContainer<Energy, ElectricPower, Box>

Transport von Zucker, Getreide:

Container<CrumblyMaterial>
MetricContainer<CrumblyMaterial, Weight>
MetricTransportableContainer<CrumblyMaterial, Weight, Silo>

Oh, was für eine Überraschung: a List<T>hat eine Dimension, die die Dinge repräsentiert, die die Liste enthalten kann; und dies ist eine Map<T, S>zweidimensionale Karte, die die Dinge darstellt, die die Karte enthalten kann, und die Zugriffstasten.

shylynx
quelle
1
Ich glaube nicht, dass Sie die Frage verstanden haben. Schauen Sie sich den letzten Absatz der Frage an.
Robert Harvey
1
@RobertHarvey Bitte lesen Sie die Frage sorgfältig durch: Der Klassenname sollte mit dem Dateinamen identisch sein. Es ist austauschbar. Das Problem liegt in der falschen Analyse der Klasse und der falschen Benennung der generischen Klassen im Allgemeinen. Um meine Antwort zusammenzufassen: "Nennen Sie es, was es ist und nicht, was es zu sein scheint."
Shylynx
1
@RobertHarvey Lesen Sie meine Antwort: Fügen Sie eine Klasse in eine Datei ein!
Shylynx
1
Ich denke, Sie verpassen den Punkt. Die Frage stellt: Wie kann ich Tuple<T1>, Tuple<T1, T2>und Tuple<T1, T2, T3>in separate CS - Dateien in einem Standardverfahren , ohne Namenskonflikte?
Robert Harvey