С добавлением класса Tuple в .net 4 я пытался решить, является ли использование их в моем дизайне плохим выбором или нет. На мой взгляд , Tuple может быть ярлыком для написания результирующего класса (я уверен, что есть и другие применения).
Итак, это:
public class ResultType
{
public string StringValue { get; set; }
public int IntValue { get; set; }
}
public ResultType GetAClassedValue()
{
//..Do Some Stuff
ResultType result = new ResultType { StringValue = "A String", IntValue = 2 };
return result;
}
Это эквивалентно этому:
public Tuple<string, int> GetATupledValue()
{
//...Do Some stuff
Tuple<string, int> result = new Tuple<string, int>("A String", 2);
return result;
}
Итак, если оставить в стороне возможность того, что я упускаю точку зрения Tuples, является ли пример с Tuple плохим выбором дизайна? Мне это кажется менее беспорядочным, но не настолько самодокументированным и чистым. Это означает, что с типом ResultType
позже станет ясно, что означает каждая часть класса, но у вас есть дополнительный код для поддержки. С помощью Tuple<string, int>
вам нужно будет посмотреть и выяснить, что каждый из них Item
представляет, но вы пишете и поддерживаете меньше кода.
Любой опыт, который вы имели с этим выбором, будет принята с благодарностью.
источник
Ответы:
Кортежи хороши, если вы управляете их созданием и использованием - вы можете поддерживать контекст, который необходим для их понимания.
Однако в общедоступном API они менее эффективны. Потребитель (а не вы) должен либо угадывать, либо искать документацию, особенно для таких вещей, как
Tuple<int, int>
.Я хотел бы использовать их для частных / внутренних членов, но использовать классы результатов для открытых / защищенных членов.
Этот ответ также имеет некоторую информацию.
источник
StringOps
(в основном это класс «методов расширения» для JavaString
) есть методparition(Char => Boolean): (String, String)
(принимает предикат, возвращает кортеж из 2 строк). Очевидно, что вывод (очевидно, что это будут символы, для которых предикат был истинным, а другой - для которых он был ложным, но не ясно, какой именно). Это документация, которая проясняет это (и сопоставление с образцом может быть использовано, чтобы прояснить при использовании, какой именно).Действительно, существуют и другие ценные варианты использования
Tuple<>
- большинство из них включают абстрагирование семантики определенной группы типов, которые имеют сходную структуру, и трактование их просто как упорядоченный набор значений. Во всех случаях преимущество кортежей состоит в том, что они избегают загромождать ваше пространство имен классами только для данных, которые предоставляют свойства, но не методы.Вот пример разумного использования для
Tuple<>
:В приведенном выше примере мы хотим представить пару противников, кортеж является удобным способом объединения этих экземпляров без необходимости создания нового класса. Вот еще один пример:
Покерную комбинацию можно рассматривать как набор карт - и кортеж (может быть) является разумным способом выражения этой концепции.
Возвращение строго типизированных
Tuple<>
экземпляров как части открытого API для открытого типа редко является хорошей идеей. Как вы сами понимаете, кортежи требуют, чтобы вовлеченные стороны (автор библиотеки, пользователь библиотеки) заранее договорились о цели и интерпретации используемых типов кортежей. Достаточно сложно создать интуитивно понятные и понятные API-интерфейсы, которыеTuple<>
публично скрывают только намерения и поведение API.Анонимные типы также являются своего рода кортежем, однако они строго типизированы и позволяют указывать понятные, информативные имена для свойств, принадлежащих типу. Но анонимные типы сложно использовать в разных методах - они были в основном добавлены для поддержки таких технологий, как LINQ, где проекции будут создавать типы, которым мы обычно не хотим назначать имена. (Да, я знаю, что анонимные типы с одинаковыми типами и именованными свойствами объединяются компилятором).
Мое эмпирическое правило таково: если вы вернете его из открытого интерфейса, сделайте его именованным типом .
Мое другое практическое правило использования кортежей: аргументы метода имени и переменные типа localc
Tuple<>
как можно более понятны - заставьте имя представлять смысл отношений между элементами кортежа. Подумай о моемvar opponents = ...
примере.Вот пример реального случая, когда я использовал,
Tuple<>
чтобы избежать объявления типа «только данные» для использования только в моей собственной сборке . Ситуация связана с тем, что при использовании общих словарей, содержащих анонимные типы, становится трудно использоватьTryGetValue()
метод для поиска элементов в словаре, поскольку для метода требуетсяout
параметр, который не может быть назван:PS Существует еще один (более простой) способ обойти проблемы, возникающие из-за анонимных типов в словарях, и заключается в использовании
var
ключевого слова, чтобы позволить компилятору «вывести» тип за вас. Вот эта версия:источник
Tuple<>
может иметь смысл. Всегда есть альтернативы ...Кортежи могут быть полезны ... но они могут быть болью позже. Если у вас есть метод, который возвращает,
Tuple<int,string,string,int>
откуда вы знаете, что эти значения позже. Были ониID, FirstName, LastName, Age
или были ониUnitNumber, Street, City, ZipCode
.источник
С точки зрения программиста на C #, кортежи являются довольно подавляющим дополнением к CLR. Если у вас есть коллекция элементов различной длины, вам не нужно иметь уникальные статические имена во время компиляции.
Но если у вас есть коллекция постоянной длины, это означает, что каждое из фиксированных местоположений в коллекции имеет определенное предопределенное значение. И в этом случае всегда лучше дать им соответствующие статические имена, чем помнить о значении
Item1
,Item2
и т.д.Анонимные классы в C # уже обеспечивают превосходное решение для наиболее частого частного использования кортежей, и они дают значимые имена элементам, так что они действительно превосходят в этом смысле. Единственная проблема заключается в том, что они не могут вытекать из именованных методов. Я бы предпочел, чтобы это ограничение было снято (возможно, только для частных методов), чем иметь особую поддержку кортежей в C #:
источник
struct var SimpleStruct {int x, int y;}
, для определения структуры с именем, которое начинается с guid, связанного с простыми структурами, и{System.Int16 x}{System.Int16 y}
добавлено что-то вроде ; любое имя, начинающееся с этого GUID, должно представлять структуру, содержащую только эти элементы и конкретное указанное содержимое; если несколько определений для одного и того же имени находятся в области видимости, и они совпадают, все будут рассматриваться как один и тот же тип.ref
параметр, единственный способ получить один делегат, который может быть передан обеим функциям, будет, если один человек создаст и скомпилирует Тип делегата и дает его другому, чтобы построить против. Никто не может указать, что эти два типа следует считать синонимами.Tuple
? Я просто просмотрел 50 мест в моей кодовой базе, где я использую кортежи, и все они либо являются возвращаемыми значениями (как правилоyield return
), либо являются элементами коллекций, которые используются где-то еще, поэтому не стоит использовать анонимные классы.Подобно ключевому слову
var
, оно предназначено для удобства, но им легко злоупотреблять.По моему наиболее скромному мнению, не выставляйте
Tuple
в качестве возвращаемого класса. Используйте его конфиденциально, если этого требует структура данных службы или компонента, но возвращайте хорошо сформированные хорошо известные классы из открытых методов.источник
var
нельзя передать назад или существовать за пределами заявленной области. однако, все еще возможно использовать это сверх его предназначенного предназначения и быть "оскорбленным"Использование класса вроде бы
ResultType
понятнее. Вы можете дать значимые имена полям в классе (тогда как с помощью кортежа они будут называтьсяItem1
иItem2
). Это еще более важно, если типы двух полей одинаковы: имя четко различает их.источник
Как насчет использования кортежей в шаблоне decorate-sort-undecorate? Преобразование Шварца для людей Perl. Вот, конечно, надуманный пример, но Tuples - хороший способ справиться с подобными вещами:
Теперь я мог бы использовать Object [] из двух элементов или в этом конкретном примере строку [] из двух элементов. Дело в том, что я мог бы использовать что угодно как второй элемент в кортеже, который используется внутри и довольно легко читается.
источник
IMO, эти "кортежи" - это в основном все анонимные
struct
типы с открытым доступом с неназванными участниками .Только место , где я хотел бы использовать кортеж , когда вам нужно быстро BLOb вместе некоторые данные, в очень ограниченном объеме. Семантика данных должна быть очевидна , поэтому код не сложен для чтения. Поэтому использование tuple (
int
,int
) для (row, col) кажется разумным. Но мне трудно найти преимущество передstruct
именованными членами (так что никаких ошибок не делается, и строка / столбец не случайно меняются местами)Если вы отправляете данные обратно абоненту или принимаете данные от абонента, вам действительно следует использовать
struct
с именованными участниками.Возьмите простой пример:
Версия кортежа
Я не вижу никакого преимущества в использовании кортежа вместо структуры с именованными членами. Использование неназванных членов - это шаг назад для читабельности и понятности вашего кода.
Tuple кажется мне ленивым способом избежать создания
struct
с настоящими именованными участниками. Чрезмерное использование кортежа, когда вы действительно чувствуете, что вам / или кому-то другому, сталкивающемуся с вашим кодом, понадобятся именованные участники - A Bad Thing ™, если я когда-либо видел его.источник
Не судите меня, я не эксперт, но теперь с новыми кортежами в C # 7.x вы можете вернуть что-то вроде:
По крайней мере, теперь вы можете назвать его, и разработчики могут увидеть некоторую информацию.
источник
Это зависит, конечно! Как вы сказали, кортеж может сэкономить ваш код и время, когда вы хотите сгруппировать некоторые элементы вместе для локального потребления. Вы также можете использовать их для создания более общих алгоритмов обработки, чем если бы вы передавали конкретный класс. Я не могу вспомнить, сколько раз мне хотелось, чтобы у меня было что-то помимо KeyValuePair или DataRow, чтобы быстро передавать некоторую дату из одного метода в другой.
С другой стороны, вполне возможно переусердствовать и обойти кортежи, где можно только догадываться, что они содержат. Если вы собираетесь использовать кортеж между классами, возможно, было бы лучше создать один конкретный класс.
Разумеется, при использовании в качестве модераторов кортежи могут привести к получению более краткого и удобочитаемого кода. Вы можете посмотреть на C ++, STL и Boost, чтобы найти примеры того, как кортежи используются в других языках, но в итоге нам всем придется поэкспериментировать, чтобы найти, как они лучше всего подходят для среды .NET.
источник
Кортежи - это бесполезная фреймворк в .NET 4. Я думаю, что в C # 4.0 была упущена отличная возможность. Я хотел бы иметь кортежи с именованными членами, чтобы вы могли получить доступ к различным полям кортежа по имени вместо Value1 , Value2 и т. Д.
Это потребовало бы изменения языка (синтаксиса), но это было бы очень полезно.
источник
let success, value = MethodThatReturnsATuple()
Лично я бы никогда не использовал Tuple в качестве возвращаемого типа, потому что нет никаких указаний на то, что представляют значения. У кортежей есть несколько полезных применений, потому что в отличие от объектов они являются типами значений и, следовательно, понимают равенство. Из-за этого я буду использовать их в качестве ключей словаря, если мне нужен многокомпонентный ключ, или в качестве ключа для предложения GroupBy, если я хочу группировать по нескольким переменным и не хочу вложенных группировок (Кто когда-либо хочет вложенные группировки?). Чтобы преодолеть проблему с чрезвычайным многословием, вы можете создать их с помощью вспомогательного метода. Имейте в виду, что если вы часто обращаетесь к членам (через Item1, Item2 и т. Д.), Вам, вероятно, следует использовать другую конструкцию, такую как struct или анонимный класс.
источник
Я использовал кортежи, как
Tuple
и новыеValueTuple
, в ряде различных сценариев и пришел к следующему выводу: не использовать .Каждый раз я сталкивался со следующими проблемами:
Мое мнение, что кортежи - это вред, а не особенность C #.
У меня несколько похожая, но гораздо менее резкая критика
Func<>
иAction<>
. Они полезны во многих ситуациях, особенно в простыхAction
иFunc<type>
вариантах, но, помимо всего прочего, я обнаружил, что создание типа делегата является более элегантным, читаемым, обслуживаемым и дает вам больше возможностей, таких какref
/out
параметры.источник
ValueTuple
и они мне тоже не нравятся. Во-первых, наименование не является сильным, это скорее предложение, очень легко испортить, потому что оно может быть назначено неявно одномуTuple
илиValueTuple
с тем же числом и типами элементов. Во-вторых, отсутствие наследования и необходимость копировать вставить все определение с места на место по-прежнему вредны.