Каков наилучший способ структурировать и называть файлы, которые содержат универсальные классы с одинаковыми именами?

14

В моем текущем проекте я столкнулся с требованием создать универсальные классы с тем же именем, но с разным количеством универсальных параметров. Например:

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

Учитывая, что я хочу все это в одном пространстве имен, я не понимаю, как структурировать и назвать мои классы и файлы?

Если мы следуем идее, что у нас должен быть класс, ограниченный одним классом на файл, и что файлы должны быть в структуре папок, которая представляет иерархию пространства имен, и что имя файла должно совпадать с именем класса, как мне справиться с этой ситуацией? ?

Что я действительно спрашиваю здесь, это то, что я должен назвать файл, который содержит MyClass<T1>, и как я должен назвать файл, который содержит MyClass<T1, T2>? Я не спрашиваю, какими должны быть имена параметров типа.

Стивен
источник
Приведите нам несколько конкретных примеров, которые описывают проблему более подробно. Приведенные вами примеры слишком ... ну, общие. Что вы подразумеваете под "как структурировать и назвать мои классы и файлы?"
Роберт Харви
Microsoft делает это самостоятельно, просто добавляя число к параметру типа. См. Документы Tuple: msdn.microsoft.com/en-us/library/…
Пит
@ Пит: Это действительно относится только к Tuple. Microsoft также использует TKey, TValueсоглашение. У Func есть TResultпараметр типа. Хотя я согласен , что вы можете использовать T1, T2и т.д. для переменного числа входных параметров , которые в противном случае не имеют конкретных целей , как TKeyи TValue.
Роберт Харви
@RobertHarvey Хорошо, да, но только в контексте фактической коллекции ключ / значение, такой как словарь. Для чего-либо, состоящего из переменного числа типов, они добавляют число. Вот еще один пример: msdn.microsoft.com/en-us/library/dd402872(v=vs.110).aspx
Пит
1
Ну, ваши изменения устарели некоторые комментарии. :) Почему вы не можете просто держать классы в одном физическом файле? Если они настолько разные, что вам нужно хранить их в отдельных файлах, то можете ли вы сказать нам, чем они отличаются?
Пит

Ответы:

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

И так далее, где число после обратного кавычка - это число параметров универсального типа. Это соглашение используется Microsoft.

Кроме того, вы можете использовать что-то вроде

MyGenericCollectionClass[TKey, TValue].cs

который сохраняет не только количество параметров универсального типа, но и их конкретные имена. Конечно, это не сохраняет угловые скобки, но мы не можем иметь в жизни все, что хотим, не так ли?

Роберт Харви
источник
1
Компилятор внутренне изменяет имя универсальных типов, добавляя обратный тик и число универсальных параметров, поскольку .NET не допускает использование нескольких типов с одним и тем же именем с различным количеством универсальных параметров, но в C # - нет. Таким образом, соглашение об именовании файлов соответствует тому, что делает компилятор.
CodesInChaos
1
Я хотел доказать, что вы не правы, но на самом деле вы правы: github.com/dotnet/corefx/tree/master/src/… Мне не нравится это соглашение.
День
1
@ Ден, кажется, что теперь они сожалеют об этом соглашении. Может быть, это подразумевает какую-то проблему? github.com/dotnet/corefx/commit/…
Сэм
@Sam Надеюсь, не проблема связи между командами Microsoft. Потому что никто больше этим не занимается. На мой взгляд, решать должна команда компиляторов, а не библиотека.
День
У меня не было бы шаров для использования "` "в имени файла.
Кристиан Э.
4

В случае Tupleи Actionчто Пит отметил, Microsoft сами используют единый файл - см Tuple.cs и Action.cs .

Я думаю, что это частично зависит от того, одинаковы ли функциональные возможности для всех классов. Лично мне не нравится объединять классы в один файл, но это может быть исключением. В исходный код, где я работаю, я добавил автоматически сгенерированный (используя T4) NamedTupleкласс, который действует так же, как Tupleи строковое имя в качестве первого аргумента в конструкторе.

Чтобы ответить на ваш вопрос, если вы не хотите использовать один файл, возможно, используйте MyClass_1.cs для MyClass<T1>, MyClass_2.cs для MyClass<T1, T2>и т. Д.

Однако ни один из этих вариантов не является идеальным, поэтому я был бы склонен предложить аргумент «Microsoft делает это таким образом, так что ...».

Вай Ха Ли
источник
2
Tupleи Actionвсе делегаты; у них нет никакого кода реализации, поэтому помещать все варианты в отдельные файлы было бы в любом случае бессмысленно. Просто доказывает, что каждое правило имеет исключение.
Роберт Харви
Да, вообще говоря, размещение нескольких открытых делегатов в одном файле считается нормальным (при условии, что они связаны).
Стивен
1
@RobertHarvey, Tupleне является делегатом, но каждая реализация в любом случае коротка.
Артуро Торрес Санчес
@ ArturoTorresSánchez: Правильно, я думал о Func.
Роберт Харви
0

Вы спрашивали себя, действительно ли у классов такое же намерение? Если один класс является более универсальным, чем другой, то это будет GenericClass , MoreGenericClass и MostGenericClass . Представьте, что каждый параметр типа класса добавляет новое измерение в класс, так что это может помочь выяснить, что это за измерение.

Давайте возьмем этот пример:

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

Я знаю, что это не лучший пример, но очень выразительно, чтобы показать три измерения:

  • Внутреннее измерение, что он может загрузить
  • Размер метрики, с помощью которого она может быть загружена, только по количеству вещей или по квадратной мере, или по кубической емкости, или по весу.
  • внешнее измерение, где оно может быть загружено.

Таким образом, вы можете моделировать перевозки автомобилей:

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

Перевозка жидкостей:

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

Транспортировка энергии:

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

Перевозка сахара, крупы:

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

О, какой сюрприз: a List<T>имеет одно измерение, представляющее то, что может содержать список; и это Map<T, S>с двумя измерениями, которые представляют вещи, которые может содержать карта, и ключи доступа.

shylynx
источник
1
Я не думаю, что вы поняли вопрос. Посмотрите на последний абзац вопроса.
Роберт Харви
1
@RobertHarvey Пожалуйста, внимательно прочитайте вопрос: имя класса должно совпадать с именем файла. Это взаимозаменяемо. Проблема заключается в неправильном анализе класса и неправильном именовании общих классов в целом. Подводя итог моему ответу: «Назови это, что это такое, а не то, что кажется».
shylynx
1
@RobertHarvey Прочитайте мой ответ: поместите один класс в один файл!
shylynx
1
Я думаю, что вы упускаете суть. Вопрос спрашивает: Как я кладу Tuple<T1>, Tuple<T1, T2>и Tuple<T1, T2, T3>в отдельные файлы CS стандартным способом, без имен столкновений?
Роберт Харви