Я декомпилировал некоторые библиотеки C # 7 и увидел, ValueTuple
что используются дженерики. Что есть ValueTuples
и почему нет Tuple
?
139
Я декомпилировал некоторые библиотеки C # 7 и увидел, ValueTuple
что используются дженерики. Что есть ValueTuples
и почему нет Tuple
?
Ответы:
A
ValueTuple
является структурой, которая отражает кортеж, такой же, как исходныйSystem.Tuple
класс.Основным отличием между
Tuple
иValueTuple
являются:System.ValueTuple
тип значения (структура), аSystem.Tuple
ссылочный тип (class
). Это имеет смысл, когда речь идет о распределении ресурсов и давлении GC.System.ValueTuple
это не толькоstruct
, это изменчивый один, и один должен быть осторожным при использовании их в качестве таковых. Подумайте, что происходит, когда класс содержитSystem.ValueTuple
поле.System.ValueTuple
выставляет свои элементы через поля вместо свойств.До C # 7 использование кортежей было не очень удобно. Их имена полей
Item1
,Item2
и т.д., и язык не поставляется синтаксис для них , как и большинства других языков делать (Python, Scala).Когда команда разработчиков языка .NET решила включить кортежи и добавить к ним синтаксический сахар на уровне языка, важным фактором была производительность. С участием
ValueTuple
того типа значения, вы можете избежать давления ГХ при их использовании , потому что (как деталь реализации) они будут выделены в стеке.Кроме того, a
struct
получает автоматическую (поверхностную) семантику равенства во время выполнения, гдеclass
- нет. Хотя команда разработчиков позаботилась о том, чтобы для кортежей было еще более оптимизированное равенство, следовательно, реализовала собственное равенство для него.Вот параграф из заметок о дизайне
Tuples
:Примеры:
Вы можете легко увидеть, что работа с
System.Tuple
очень быстро становится неоднозначной. Например, скажем, у нас есть метод, который вычисляет сумму и количествоList<Int>
:На приемном конце мы получаем:
Способ, которым вы можете деконструировать кортежи значений в именованные аргументы, является реальной силой функции:
И на приемном конце:
Или:
Полезности компилятора:
Если мы посмотрим под прикрытием нашего предыдущего примера, мы можем увидеть, как именно интерпретатор интерпретирует,
ValueTuple
когда мы просим его деконструировать:Внутренне, скомпилированный код использует
Item1
иItem2
, но все это абстрагировано от нас, так как мы работаем с декомпозированным кортежем. Кортеж с именованными аргументами аннотируется с помощьюTupleElementNamesAttribute
. Если вместо разложения мы используем одну свежую переменную, мы получим:Обратите внимание , что компилятор все еще должен сделать некоторое волшебство произойдет ( с помощью атрибута) , когда мы отладить приложение, как это было бы странно видеть
Item1
,Item2
.источник
var (sum, count) = DoStuff(Enumerable.Range(0, 10));
Разница между
Tuple
и вValueTuple
том, чтоTuple
это ссылочный тип иValueTuple
тип значения. Последнее желательно, потому что изменения в языке в C # 7 используют кортежи гораздо чаще, но выделение нового объекта в куче для каждого кортежа является проблемой производительности, особенно когда это не нужно.Однако в C # 7 идея заключается в том, что вам никогда не придется явно использовать любой тип из-за синтаксического сахара, добавляемого для использования кортежем. Например, в C # 6, если вы хотите использовать кортеж для возврата значения, вам придется сделать следующее:
Однако в C # 7 вы можете использовать это:
Вы даже можете пойти дальше и дать имена значений:
... Или полностью разобрать кортеж:
Кортежи не часто использовались в C # pre-7, потому что они были громоздкими и многословными, и действительно использовались только в тех случаях, когда создание класса / структуры данных только для одного экземпляра работы было бы большим трудом, чем оно того стоило. Но в C # 7 кортежи теперь имеют поддержку на уровне языка, поэтому их использование намного чище и полезнее.
источник
Я посмотрел на источник для обоих
Tuple
иValueTuple
. Разница в том, чтоTuple
этоclass
иValueTuple
есть то,struct
что реализуетIEquatable
.Это означает, что
Tuple == Tuple
будет возвращаться,false
если они не являются одним и тем же экземпляром, ноValueTuple == ValueTuple
будет возвращаться,true
если они одного типа, иEquals
возвращаетtrue
для каждого из значений, которые они содержат.источник
Другие ответы забыли упомянуть важные моменты. Вместо того, чтобы перефразировать, я буду ссылаться на документацию XML из исходного кода :
Типы ValueTuple (от 0 до 8) включают реализацию времени выполнения, которая лежит в основе кортежей в C # и структурных кортежей в F #.
Помимо созданного с помощью синтаксиса языка , они легче всего создаются с помощью
ValueTuple.Create
фабричных методов. ЭтиSystem.ValueTuple
типы отличаются отSystem.Tuple
типов тем , что:С введением этого типа и компилятора C # 7.0 вы можете легко написать
И вернуть два значения из метода:
В отличие от
System.Tuple
вас, вы можете обновить его члены (изменяемые), потому что они являются открытыми полями для чтения и записи, которым можно дать значимые имена:источник
class MyNonGenericType : MyGenericType<string, ValueTuple, int>
и т. Д.В дополнение к комментариям, приведенным выше, одна неприятная особенность ValueTuple заключается в том, что в качестве типа значения именованные аргументы стираются при компиляции в IL, поэтому они не доступны для сериализации во время выполнения.
то есть ваши аргументы с именами по-прежнему будут заканчиваться как "Item1", "Item2" и т. д. при сериализации через, например, Json.NET.
источник
Позднее присоединение, чтобы добавить краткое пояснение к этим двум фактоидам:
Можно было бы подумать, что массовое изменение значений-кортежей будет простым:
Кто-то может попытаться обойти это так:
Причиной такого причудливого поведения является то, что кортежи-значения точно основаны на значениях (структурах), и поэтому вызов .Select (...) работает с клонированными структурами, а не с оригиналами. Для решения этой проблемы мы должны прибегнуть к:
В качестве альтернативы, конечно, можно попробовать простой подход:
Надеюсь, что это помогает кому-то изо всех сил пытаться сделать хвосты из размещенных в списках значений-кортежей.
источник