Яка хороша угода про іменування для загальних типів у C #? [зачинено]


16

Я вирішив поставити це питання тут, а не на переповнення стека, оскільки це досить суб'єктивно.

У C #, як правило, я бачу загальні типи з дуже бідними назвами. Зокрема, "T" зазвичай використовується, але сама по собі не є змістовною назвою. Наприклад:

class Fruit<T>
{
    T fruit;
}

Хоча це типовий підхід, хтось рекомендував би проти цього? І якщо так, то яка розумна умова іменування для родових типів у контексті C # для загальних функцій та класів?

У попередньому прикладі припустимо, що родовий тип Tзавжди повинен бути типом фруктів, таким як Appleабо Orange. Тип Tповинен зробити очевидним, що це тип фруктів, тому, можливо, краща назва буде FruitType, тому ми закінчимо:

class Fruit<FruitType>
{
    FruitType fruit;
}

Це просто для того, щоб дати вам хлопці уявлення про те, що я шукаю. Що є прийнятним "правилом" для цього питання?


3
Це не конструктивне питання. Відповіді він отримає лише з улюбленим стилем плаката.
Майкл К

1
Погляньте на обмеження, розглядаючи ваш приклад: msdn.microsoft.com/en-us/library/d5x73970.aspx#Y426
Matthieu

2
@Michael буде ряд відповідей, і прийнята відповідь стане улюбленою Робертом, але за різні інші відповіді будуть озвучені.
StuperUser

5
@Michael Суб'єктивне запитання отримує суб'єктивну відповідь. Питання все ще є конструктивним, оскільки воно служить орієнтиром для всіх, хто хоче різноманітних ідей / рішень цієї конкретної проблеми. Той, який я позначаю як відповідь, не представляє єдиного корисного біта інформації.
void.pointer

Можливо, перетворіть це на вікі спільноти, як хороший, хоча суб'єктивний, ресурс?
тилермах

Відповіді:


22

Це дійсно суб'єктивно ... іш .
Оскільки деякі люди вважають i, що цілком відповідає дійсності для змінної циклу, деякі вважають, що Tвона цілком справедлива для типу власника місць у загальному класі.

Я особисто підтримую такий підхід, це загальна конвенція, і люди взагалі знають, що ви маєте на увазі.

Там, де тип є значущим, я б використовував значущу назву, але, як правило, почніть його з T. Я нещодавно розробив загальний клас словника (не запитуйте), і декларація була

public class Dictionary<TKey, TValue>

Однак для чогось подібного до кортежу, де типи є по суті безглуздими, я вважаю наступне цілком прийнятним.

public class Tuple<T1, T2, T3>

2
Я взагалі не вважаю це суб'єктивним. iі Tпрацюйте, і це в принципі вимірюється (тобто вимірюється, чи збільшується розуміння вихідного коду, якщо, скажімо, індекси циклу отримують різні ідентифікатори). Тільки тому, що важко виміряти, це не означає, що нам потрібно тегувати "суб'єктивну" етикетку на всьому. Зважаючи на широке використання без очевидних проблем, цілком розумно сказати, навіть не вимірюючи, що це насправді працює.
Конрад Рудольф

2
@Konrad: Ви маєте бал. . . однак питання не позначене як суб'єктивне, запитуючий особа визнає, що це суб'єктивна тема, припускаючи, що люди, як правило, мають власні переваги щодо конвенцій про іменування. Тому, хоча питання може бути не суб'єктивним (а фактично це не так, як є правильна відповідь, тобто відповідь, що посилається на офіційне керівництво Microsoft), тема є суб'єктивною, оскільки я впевнений, що хтось опублікує повідомлення " iі Tє злими . Ніколи не треба вживати однієї літери імена". Додали іш, щоб допомогти усім задовольнити :)
Бінарний Вор'єр

1
Я думаю, що коментарі, додані до цієї публікації, дають дуже важливу відповідь, хоча сама відповідь дуже корисна. Tє сенс, коли ми говоримо про тип без обмежень, TFruitмає сенс, тому що він каже мені "Будь-який тип із обмеженням, що це плід". Це здається хорошим "правилом" для іменування параметрів загального типу. Спасибі!!
void.pointer

1
Зауважимо лише, що це узгоджується з Керівними принципами .NET Framework Design для розробників бібліотеки з MSDN. Див.: Назви параметрів загального типу .
Грант Томас

7

Я думаю, ти маєш рацію, хоча Т став уже цілком стандартним. Це, мабуть, походить із старих часів С ++ та формулювання "типу T". Я вважаю гарною практикою бути максимально описовим, але це суб'єктивно.

Ви можете вибрати T як префікс, як і багато людей, які обирають I для інтерфейсів. Таким чином

class Juice<TFruit> where TFruit...

було б гарним ім'ям на мою скромну думку. Я віддаю перевагу префіксам суфіксів у більшості випадків, оскільки тут прямо зрозуміло, що ви бачите, коли натрапляєте на нього, і простіше шукати такі речі, як Intellisense. Це також є хорошою практикою для UI-Controls, коли ви, швидше за все, завжди знаєте тип (наприклад, TextBox), але не на 100% впевнені в описовому імені, яке ви йому дали.

Негативна сторона його полягає в тому, що це виглядає погано, коли сам тип починається з Т. Тож я думаю, що було б добре суфікс загального типу в особливих випадках, як той, що нижче.

class SomeAlgorithm<TypeT> where TypeT : Type

Зверніть увагу, що це лише моя думка і дуже суб'єктивна. Але я думаю, що у мене є незначний момент, коли я віддаю перевагу префіксам суфіксам.


Використання Tпрефікса для параметрів типу та Iімен інтерфейсів явно потрібно ( правила " DO ...") в Рамкових рекомендаціях щодо дизайну.
Річард

1
Сумнівно, що використання TFruitтут приносить до столу T. Використання назви, наприклад, TTypeабо TypeT, безумовно, дурниця. Він не додає жодної інформації, що перевищує просто T. Точно та сама інформація передається.
Конрад Рудольф

@Konrad Rudolph: Подивіться уважно на мій приклад TypeT, він охоплює особливий випадок, коли йдеться про System.Type. Я думаю, що мої імена мають більш високу ентропію, ніж просто використання Т для типу, особливо якщо загальне також обмежене.
Сокіл

7

Microsoft має офіційне керівництво щодо генеричних даних: Назви класів, структур та інтерфейсів (цитується тут і в книжковій формі: Настанови щодо дизайну рамок ).

Щодо конкретного запитання, він говорить:

Назвіть параметри загального типу з описовими іменами, якщо тільки однолітерне ім’я не є повністю зрозумілим і описове ім'я не додасть значення.

IDictionary<TKey, TValue> 

є прикладом інтерфейсу, який відповідає цьому керівництву.

Розглянемо використання літери T як назви параметра параметра типу для типів з одним однобуквеним параметром типу.

Здійснюйте префікси описових імен параметрів типу буквою Т.

Розглянемо вказівку обмежень, розміщених на параметрі типу у назві параметра. Наприклад, параметр, обмежений ISession, може називатися TSession.


Кращою посиланням буде книга керівництва по дизайну рамок або (підсумок) про MSDN, зокрема назви класів, структур та інтерфейсів .
Річард

@Richard: коригував мою відповідь з огляду на ваш коментар, Дякую!
Матьє

2

Вся суть генерики полягає в делегуванні функціональності - загальний клас робить одне, а його аргумент - інше. Приклад підручника - це загальна колекція: колекція зберігає «речі», але байдуже, що це за речі. Таким чином, загальне ім'я (sic!) Має певну логіку - ми не хочемо, щоб воно було описовим, тому що немає нічого іншого, окрім як "це аргумент загального типу", який назва Tмістить вичерпно (враховуючи конвенція). Бути описовим - це добре, але надмірно описовий говорить про обмеження, яких там немає.

Однак іноді в загальному класі чи методі є більше одного параметра типу, і в цей момент є сенс надати їм більш описові назви, щоб їх роль стала очевидною. Хорошим прикладом може бути тип колекції ключових значень, де і ключ, і значення є загальними; зателефонувати їм Tта S(або що Qзавгодно) було б менш корисним, ніж називати їх, скажімо, KeyTypeі ValueType, або TKeyі TVal.


1

Відповідь справді суб’єктивна. Однак це має користь як питання, оскільки код повинен самостійно документувати, і ми, можливо, всі зможемо дізнатися про кращі способи зробити це.

Нижче наведені умовні положення, яких я вивчив і дотримуюся:

  • Параметри загального типу ніколи не повинні бути помилковими для конкретних класів. Це, як правило, заохочує передмову Tнезалежно від того, що випливає, як і інтерфейси, як правило, попередньо I.

  • Один параметр загального типу для класу або методу, як правило, повинен бути маркований T. Це майже загальновизнана конвенція, що датується шаблонами C ++.

  • Кілька параметрів загального типу для одного і того ж класу або декларації методу повинні починатись з T, але бути диференційованими деякими стислими, але зрозумілими способами. TInі TOut, наприклад, є загальними і добре зрозумілими GTP для методу, який приймає сильно типізований загальний вхід і виробляє сильно типізований загальний вихід.

  • Кілька диференційованих, але не примітних типів, таких як такий, що містить клас типу .Net's Tuple або делегат типів, таких як Func, предикат і дія, можуть бути позначені T1, T2, T3 тощо. Однак, "чудові" декларації GTP (мають певну мету і / або дуже конкретні обмеження типу) повинні мати щось більш описовий.

  • Один родовий тип методу, який відрізняється від загального типу класу, що містить, може або слідувати попередньому правилу щодо декількох типів у класі чи методі, АБО якщо тип не відрізняється від відмінності від того, що він відрізняється, йому можна надати інший одна буква, часто Uабо V. Це знову умова, що датується шаблонами C ++.

  • Що б ви не вирішили зробити, дотримуйтесь цього; не позначати GTP для одного класу Tі для наступного TParam, якщо другий клас вкладений у перший, не Tдоступний для використання у другому.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.