Was ist eine gute Namenskonvention für generische Typen in C #? [geschlossen]

16

Ich habe mich dazu entschlossen, diese Frage hier zu stellen, anstatt auf Stapelüberlauf, da sie eher subjektiv ist.

In C # sehe ich normalerweise generische Typen mit sehr schlechten Namen. Insbesondere wird "T" häufig verwendet, ist jedoch für sich genommen kein aussagekräftiger Name. Beispielsweise:

class Fruit<T>
{
    T fruit;
}

Während dies der typische Ansatz ist, würde jemand dagegen empfehlen? Und wenn ja, was wäre eine sinnvolle Namenskonvention für generische Typen im Kontext von C # für generische Funktionen und Klassen?

Nehmen wir in meinem vorherigen Beispiel an, dass der generische Typ Timmer ein Obsttyp wie Appleoder sein muss Orange. Der Typ Tmuss deutlich machen, dass es sich um eine Obstsorte handelt. Ein besserer Name wäre also FruitType:

class Fruit<FruitType>
{
    FruitType fruit;
}

Dies ist nur, um euch eine Vorstellung davon zu geben, wonach ich suche. Was ist eine akzeptable Faustregel für dieses Problem?

void.pointer
quelle
3
Dies ist keine konstruktive Frage. Es werden nur Antworten mit dem Lieblingsstil des Posters angezeigt.
Michael K
1
Betrachten Sie die Einschränkungen anhand
Matthieu,
2
@Michael es wird eine Reihe von Antworten geben, und die akzeptierte Antwort wird Roberts Favorit sein, aber verschiedene andere Antworten werden bewertet.
StuperUser
5
@Michael Eine subjektive Frage bekommt eine subjektive Antwort. Die Frage ist immer noch konstruktiv, da sie als Bezugspunkt für alle dient, die eine Vielzahl von Ideen / Lösungen für dieses spezielle Problem wünschen. Die Antwort, die ich als Antwort markiere, ist nicht die einzige nützliche Information.
void.pointer
Vielleicht in ein Community-Wiki verwandeln, als gute, wenn auch subjektive Ressource?
tylermac

Antworten:

22

Es ist in der Tat subjektiv ... ish .
Einige Leute finden i, dass dies für eine for-Schleifenvariable durchaus gilt, andere denken, dass dies Tfür einen Typplatzhalter in einer generischen Klasse durchaus gilt.

Ich persönlich unterstütze diesen Ansatz, es ist eine übliche Konvention und die Leute wissen im Allgemeinen , was Sie meinen.

Wo der Typ aussagekräftig ist, verwende ich einen aussagekräftigen Namen, aber beginne ihn im Allgemeinen mit T. Vor kurzem habe ich eine generische Dictionary-Klasse entwickelt (fragen Sie nicht), und die Deklaration war

public class Dictionary<TKey, TValue>

Für etwas wie ein Tupel, bei dem die Typen im Wesentlichen bedeutungslos sind, halte ich jedoch Folgendes für vollkommen akzeptabel.

public class Tuple<T1, T2, T3>
Binary Worrier
quelle
2
Ich finde das überhaupt nicht subjektiv. iund TArbeit, und dies ist im Prinzip messbar (dh es ist messbar, ob das Verständnis des Quellcodes zunimmt, wenn beispielsweise Schleifenindizes unterschiedliche Bezeichner erhalten). Nur weil es schwer zu messen ist, heißt das nicht, dass wir das „subjektive“ Etikett auf allem markieren müssen. Angesichts des breiten Einsatzes ohne offensichtliche Probleme ist es durchaus sinnvoll zu sagen, auch ohne zu messen, dass dies tatsächlich funktioniert.
Konrad Rudolph
2
@Konrad: Du hast einen Punkt. . . Die Frage ist jedoch nicht als subjektiv gekennzeichnet. Der Fragesteller gibt zu, dass es sich um ein subjektives Thema handelt, vorausgesetzt, dass die Leute ihre eigenen Vorlieben für Namenskonventionen haben. Obwohl die Frage möglicherweise nicht subjektiv ist (und in der Tat nicht, weil es eine korrekte Antwort gibt, dh die Antwort, die auf die offizielle Microsoft-Richtlinie verweist), ist das Thema subjektiv, da ich sicher bin, dass jemand eine Frage posten wird " iund Tsind böse . Man darf niemals einzelne Buchstaben verwenden", tippe answer. Habe ein ish hinzugefügt , um alle zufriedenzustellen :)
Binary Worrier
1
Ich denke, allein die Kommentare, die zu diesem Beitrag hinzugefügt wurden, machen ihn zu einer sehr wertvollen Antwort, obwohl die Antwort selbst sehr hilfreich ist. TSinnvoll, wenn es sich um einen Typ ohne Einschränkungen handelt. Sinnvoll, TFruitweil er zu mir sagt: "Jeder Typ mit der Einschränkung, dass es sich um eine Frucht handelt." Dies scheint eine gute "Faustregel" für die Benennung generischer Typparameter zu sein. Vielen Dank!!
void.pointer
1
Dies entspricht den .NET Framework-Entwurfsrichtlinien für Bibliotheksentwickler von MSDN. Siehe: Namen von generischen Typparametern .
Grant Thomas
7

Ich denke, Sie haben Recht, obwohl T ein ziemlicher Standard geworden ist. Es stammt wahrscheinlich aus der alten C ++ - Zeit und dem Wortlaut "vom Typ T". Ich halte es für eine gute Praxis, so beschreibend wie möglich zu sein, aber das ist subjektiv.

Sie könnten T als Präfix wählen, ähnlich wie viele Leute I für Schnittstellen wählen. Somit

class Juice<TFruit> where TFruit...

wäre meiner bescheidenen meinung nach ein guter name. Ich bevorzuge Präfixe gegenüber Suffixen in den meisten Fällen, da sofort klar ist, was Sie sehen, wenn Sie darauf stoßen, und es einfacher ist, mit Dingen wie Intellisense zu suchen. Dies ist auch für Benutzeroberflächen-Steuerelemente eine gute Praxis, wenn Sie den Typ (z. B. TextBox) mit hoher Wahrscheinlichkeit immer kennen, sich aber nicht hundertprozentig sicher sind, welchen beschreibenden Namen Sie ihm gegeben haben.

Das Negative daran ist, dass es schlecht aussieht, wenn der Typ selbst mit T beginnt. Ich halte es also für eine gute Sache, den generischen Typ in besonderen Fällen wie dem folgenden anzufügen.

class SomeAlgorithm<TypeT> where TypeT : Type

Bitte beachten Sie, dass dies nur meine Meinung und sehr subjektiv ist. Aber ich glaube, ich habe ein kleines Problem damit, Präfixe den Suffixen vorzuziehen.

Falke
quelle
Die Verwendung eines TPräfixes für Typparameter und Ifür Schnittstellennamen ist in den Framework Design Guidelines ausdrücklich erforderlich (" DO ..." - Regeln).
Richard
1
Es ist fraglich, was die Verwendung TFruithier auf den Tisch bringt T. Verwenden von Namen wie TTypeoder TypeTist sicherlich Unsinn. Es fügt einfach keinerlei Informationen hinzu T. Genau die gleichen Informationen werden übermittelt.
Konrad Rudolph
@Konrad Rudolph: Schauen Sie sich mein Beispiel für TypeT genau an, es behandelt einen Sonderfall beim Umgang mit System.Type. Ich denke, meine Namen haben eine höhere Entropie als nur die Verwendung von T für den Typ, besonders wenn das Generikum ebenfalls eingeschränkt ist.
Falcon
7

Microsoft hat eine offizielle Richtlinie in Bezug auf Generika: Namen von Klassen, Strukturen und Schnittstellen ( hier und in Buchform: Framework Design Guidelines ).

In Bezug auf Ihre spezifische Frage heißt es:

Benennen Sie generische Typparameter mit beschreibenden Namen, es sei denn, ein aus einem Buchstaben bestehender Name ist vollständig selbsterklärend und ein beschreibender Name würde keinen Mehrwert bringen.

IDictionary<TKey, TValue> 

ist ein Beispiel für eine Schnittstelle, die dieser Richtlinie folgt.

Verwenden Sie den Buchstaben T als Typparameternamen für Typen mit einem einzelnen Typparameter.

Stellen Sie beschreibenden Typparameternamen den Buchstaben T voran.

Erwägen Sie, Einschränkungen für einen Typparameter im Namen des Parameters anzugeben. Beispielsweise kann ein auf ISession beschränkter Parameter TSession genannt werden.

Matthieu
quelle
Eine bessere Referenz wäre das Framework Design Guidelines- Buch oder die (Zusammenfassung) zu MSDN, insbesondere Namen von Klassen, Strukturen und Schnittstellen .
Richard
@Richard: habe meine Antwort unter Berücksichtigung deines Kommentars angepasst, danke!
Matthieu
2

Der springende Punkt bei Generika ist, Funktionalität zu delegieren - die generische Klasse macht eine Sache, ihr Argument macht eine andere. Das Lehrbuchbeispiel ist eine generische Sammlung: Die Sammlung speichert "Dinge", aber es ist egal, was diese Dinge sind. Ein generischer Name (sic!) Hat also eine gewisse Logik - wir wollen nicht, dass er beschreibend ist, denn es gibt nichts anderes zu beschreiben als "es ist das generische Typargument", das der Name Tausführlich umfasst (wenn man bedenkt) Das Treffen). Beschreibend zu sein ist gut, aber zu beschreibend zu sein deutet auf Einschränkungen hin, die es nicht gibt.

Manchmal hat eine generische Klasse oder Methode jedoch mehr als einen Typparameter, und an dieser Stelle ist es sinnvoll, ihnen aussagekräftigere Namen zu geben, damit ihre Rolle offensichtlich wird. Ein gutes Beispiel wäre ein Auflistungstyp für Schlüsselwerte, bei dem sowohl Schlüssel als auch Wert generisch sind. Sie anzurufen Tund S(oder Qwas auch immer) wäre weniger nützlich als sie anzurufen, sagen wir, KeyTypeund ValueType, oder TKeyund TVal.

tdammers
quelle
1

Die Antwort ist in der Tat subjektiv. Es ist jedoch eine wichtige Frage, da sich Code selbst dokumentieren sollte, und wir könnten möglicherweise alle lernen, wie man es besser macht.

Das Folgende sind die Konventionen, die ich gelernt habe und die ich befolge:

  • Generische Typparameter sollten niemals mit konkreten Klassen verwechselt werden können. Dies fördert im Allgemeinen ein Vorwort, Tunabhängig davon, was folgt, ähnlich wie Schnittstellen im Allgemeinen vorangestellt werden I.

  • Ein einzelner generischer Typparameter für eine Klasse oder Methode sollte in der Regel gekennzeichnet werden T. Dies ist eine nahezu universelle Konvention, die auf C ++ - Vorlagen zurückgeht.

  • Mehrere generische Typparameter in derselben Klassen- oder Methodendeklaration sollten alle mit T beginnen, sich jedoch durch einige prägnante, aber verständliche Mittel unterscheiden. TInund TOutzum Beispiel sind gängige und gut verstandene GTPs für eine Methode, die eine stark typisierte generische Eingabe akzeptiert und eine stark typisierte generische Ausgabe erzeugt.

  • Mehrere differenzierte, aber unauffällige Typen, z. B. für eine übergeordnete Klasse wie .Net's Tuple oder Delegate-Typen wie Func, Predicate und Action, können als T1, T2, T3 usw. bezeichnet werden. "Bemerkenswerte" GTP-Deklarationen (mit einem bestimmten Zweck und / oder sehr spezifische Typeinschränkungen) sollten etwas aussagekräftigeres haben.

  • Ein einzelner generischer Typ in einer Methode, der sich vom generischen Typ einer enthaltenden Klasse unterscheidet, kann entweder der vorherigen Regel in Bezug auf mehrere Typen in einer Klasse oder Methode folgen, ODER wenn der Typ nicht auffällig ist, sondern sich unterscheidet, kann ihm ein anderer Typ zugewiesen werden einzelner Buchstabe, oft Uoder V. Dies ist wieder eine Konvention, die auf C ++ - Vorlagen zurückgeht.

  • Was auch immer Sie tun, halten Sie es konsistent; Beschriften Sie ein GTP nicht für eine Tund die nächste Klasse , es TParamsei denn, die zweite Klasse ist in der ersten verschachtelt und kann in der zweiten Tnicht verwendet werden.

KeithS
quelle