Для решения какого требования был разработан кортеж?


94

Я смотрю на новую функцию C # кортежей. Мне любопытно, для решения какой проблемы был разработан кортеж?

Для чего вы использовали кортежи в своих приложениях?

Обновить

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

var coords = Tuple.Create(geoLat,geoLong);

Затем используйте кортеж так:

var myLatlng = new google.maps.LatLng("+ coords.Item1 + ", "+ coords.Item2 + ");

Это правильно?



4
Что ж, я могу придумать два ответа ...
Noon Silk,

13
Если понятие «координата» имеет смысл как класс, я бы сделал его классом. Используйте кортежи в тех случаях, когда нет какой-либо разумной концепции «бизнес-логики» для набора данных, оправдывающей создание типа.
Эрик Липперт

13
Координаты - не лучший пример кортежа. Кортеж в C # - это просто специальное решение в случаях, когда вам нужно вернуть (из функции) два значения. Вместо того, чтобы устанавливать один тип результата плюс один выходной параметр, более элегантно вернуть один кортеж. Таким образом, вам не нужно заранее объявлять второй параметр. Разница еще более очевидна в C ++ (вы можете констатировать результат, но не можете константировать параметр out / ref).
greenoldman

8
Потому что у python это было, а у python не может быть ничего, чего нет в C #;)
Эван Плейс,

Ответы:


117

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

Многие языки программирования позволяют логически сгруппировать набор значений, не связанных друг с другом, без создания типа только одним способом:

void M(int foo, string bar, double blah)

Логически это в точности то же самое, что и метод M, который принимает один аргумент, который является кортежем из трех типов int, string, double. Но я надеюсь, что вы на самом деле не сделаете:

class MArguments
{
   public int Foo { get; private set; } 
   ... etc

если только MArguments не имеют другого значения в бизнес-логике.

Концепция «сгруппировать вместе набор не связанных друг с другом данных в некую структуру, более легкую, чем класс», полезна во многих, многих местах, а не только для формальных списков параметров методов. Это полезно, когда метод имеет две вещи, которые нужно вернуть, или когда вы хотите создать словарь из двух данных, а не из одного, и так далее.

Такие языки, как F #, которые изначально поддерживают типы кортежей, предоставляют пользователям большую гибкость; они представляют собой чрезвычайно полезный набор типов данных. Команда BCL решила работать с командой F # над стандартизацией одного типа кортежей для фреймворка, чтобы каждый язык мог получить от них пользу.

Однако на данный момент для кортежей в C # нет языковой поддержки. Кортежи - это просто еще один тип данных, как и любой другой класс фреймворка; в них нет ничего особенного. Мы рассматриваем возможность добавления улучшенной поддержки кортежей в гипотетических будущих версиях C #. Если у кого-то есть какие-либо мысли о том, какие функции, связанные с кортежами, вы хотели бы видеть, я был бы счастлив передать их команде разработчиков. Реалистичные сценарии более убедительны, чем теоретические размышления.


1
@MalcomTucker: Асинхронность и параллелизм определенно находятся в наших умах как богатые области, где языковые инструменты могут быть использованы для решения реальных проблем. Я не думаю, что асинхронные рабочие процессы в стиле F # обязательно лучше всего подходят для C #, но они определенно вдохновляют.
Эрик Липперт

60
Хотя кортежи полезны, один большой недостаток - ясность. Трудно читать и понимать код, который относится к Item1и Item2т. Д. Если кортежи когда-либо получат языковую поддержку в C #, было бы замечательно разрешить их членам именоваться (или, по крайней мере, использовать псевдонимы) таким образом, чтобы разрешить код, использующий чтобы они были более понятными. В таком гипотетическом будущем я бы также хотел видеть кортежи соответствующей «формы» как допустимые параметры для методов, которые принимают индивидуальные параметры (и наоборот). Итак, Tuple<int,string,bool>можно перейти к M(int,string,bool). Это сделало бы методы запоминания намного проще.
LBushkin

2
Эти «кортежи» в основном представляют собой анонимные типы publicдоступа с безымянными членами . Я бы предпочел, чтобы программист написал a с именованными членами и вернул это, чем имел дело с a, который ничего не говорит мне о семантике своих членов. structstructtuple
bobobobo

1
@ Hi-Angel: Аргумент не о том, что считается кортежем, а что нет, а скорее о том, какой набор функций могут использовать современные бизнес-разработчики для повышения своей производительности . Л.Бушкин выражает просьбу о функции, которую команда дизайнеров слышит постоянно: желание сделать какой-то «тип записи» без проблем и затрат на создание всего класса только для нескольких полей. В C # уже есть эта функция для методов; это называется «список параметров».
Эрик Липперт

2
@ Hi-Angel: Вы, вероятно, не стали бы приводить аргумент «если вы хотите получить доступ к параметрам вашего метода по имени, вам следует создать отдельный класс», потому что это кажется чрезвычайно тяжелым, но это только кажется тяжелым, потому что мы привыкли к возможность мгновенно связать набор произвольных переменных с произвольными типами и именами при вызове метода . Представьте, что ни в одном языке нет такой возможности; каждый метод может принимать только один аргумент, и если вы хотите передать два, вам нужно будет создать тип и передать его экземпляр.
Эрик Липперт

22

Кортежи обеспечивают неизменяемую реализацию коллекции

Помимо обычного использования кортежей:

  • группировать общие ценности вместе без создания класса
  • чтобы вернуть несколько значений из функции / метода
  • и т.д...

Неизменяемые объекты по своей природе потокобезопасны:

Неизменяемые объекты могут быть полезны в многопоточных приложениях. Несколько потоков могут действовать с данными, представленными неизменяемыми объектами, не беспокоясь о том, что данные изменяются другими потоками. Поэтому неизменяемые объекты считаются более потокобезопасными, чем изменяемые объекты.

Из «Неизменяемого объекта» в Википедии


Спасибо, что добавили дополнительную информацию к вопросу. Очень признателен.
Chaddeus

Если вам нужна неизменяемая коллекция, вы должны использовать неизменяемую коллекцию, а не Tuple. Разница в том, что для большинства неизменяемых коллекций вам не нужно указывать количество элементов во время компиляции
BlueRaja - Danny Pflughoeft

@ BlueRaja-DannyPflughoeft Когда я писал этот ответ, неизменные классы коллекций C # еще не были доступны в BCL. Думаю, я заменю «коллекцию» на «объект», поскольку MS стерилизовала реализацию Tuple на C #
Эван Плэйс

12

Он предоставляет альтернативу refилиout если у вас есть метод, который должен возвращать несколько новых объектов как часть своего ответа.

Он также позволяет вам использовать встроенный тип в качестве возвращаемого типа, если все, что вам нужно сделать, это смешать два или три существующих типа, и вы не хотите добавлять класс / структуру только для этой комбинации. (Вы когда-нибудь хотели, чтобы функция возвращала анонимный тип? Это частичный ответ на эту ситуацию.)


Черт. Ницца. Хотел бы я проверить, что такое кортежи несколько лет назад;).
sabiland 02

10

Часто бывает полезно иметь тип «пара», просто используемый в быстрых ситуациях (например, при возврате двух значений из метода). Кортежи - это центральная часть функциональных языков, таких как F #, и C # взял их на вооружение.


System.Web.UI имеет класс пары msdn.microsoft.com/en-us/library/system.web.ui.pair.aspx .
StingyJack


4

Лично я считаю, что кортежи являются итеративной частью разработки, когда вы находитесь в исследовательском цикле или просто «играете». Поскольку кортеж является универсальным, я склонен думать об этом при работе с универсальными параметрами - особенно когда я хочу разработать общий фрагмент кода, и я начинаю с конца кода, вместо того чтобы спрашивать себя: «Как бы мне понравился этот вызов? смотреть?".

Довольно часто я понимаю, что коллекция, которую формирует Tuple, становится частью списка, и взгляд на List> на самом деле не выражает намерения списка или того, как он работает. Я часто «живу» с этим, но обнаруживаю, что хочу манипулировать списком и изменять значение - в этот момент я не обязательно хочу создавать для этого новый кортеж, поэтому мне нужно создать свой собственный класс или структуру. чтобы удерживать его, поэтому я могу добавить код манипуляции.

Конечно, всегда есть методы расширения, но довольно часто вы не хотите распространять этот дополнительный код на общие реализации.

Были времена, когда я хотел выразить данные как кортеж, но не имел доступных кортежей. (VS2008) и в этом случае я только что создал свой собственный класс Tuple и не делаю его потокобезопасным (неизменяемым).

Итак, я полагаю, я придерживаюсь мнения, что кортежи - это ленивое программирование за счет потери имени типа, описывающего его назначение. Другой расход заключается в том, что вы должны объявить подпись кортежа, где бы он ни использовался в качестве параметра. После ряда методов, которые начинают выглядеть раздутыми, вы можете почувствовать, как и я, что стоит создать класс, поскольку он очищает сигнатуры методов.

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

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

Если у меня есть возможность провести рефакторинг кода, я часто сомневаюсь, что в нем находится кортеж.


3

Старый вопрос с 2010 года, а теперь в 2017 году Дотнет меняется и становится умнее.

В C # 7 представлена ​​языковая поддержка кортежей, которая позволяет использовать семантические имена для полей кортежа с использованием новых, более эффективных типов кортежей.

В vs 2017 и .Net 4.7 (или при установке пакета nuget System.ValueTuple) вы можете создать / использовать кортеж очень эффективным и простым способом:

     var person = (Id:"123", Name:"john"); //create tuble with two items
     Console.WriteLine($"{person.Id} name:{person.Name}") //access its fields

Возврат нескольких значений из метода:

    public (double sum, double average) ComputeSumAndAverage(List<double> list)
    {
       var sum= list.Sum();
        var average = sum/list.Count;
        return (sum, average);
    }

    How to use:

        var list=new List<double>{1,2,3};
        var result = ComputeSumAndAverage(list);
        Console.WriteLine($"Sum={result.sum} Average={result.average}");    

Подробнее читайте: https://docs.microsoft.com/en-us/dotnet/csharp/tuples.


1

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


1

Возвращение более одного значения из функции. getCoordinates () не очень полезен, если он просто возвращает x, y или z, но создание полного класса и объекта для хранения трех целых чисел также кажется довольно тяжелым.


1

Обычно используется, чтобы избежать создания классов / структур, содержащих только 2 поля, вместо этого вы создаете Tuple (или KeyValuePair на данный момент). Полезно как возвращаемое значение, избегайте передачи N параметров ...


0

Я обнаружил, что KeyValuePair обновляется в C # для перебора пар ключ-значение в словаре.


KeyValuePairможно рассматривать как специальный обходной путь. В Python перебор dictпросто возвращает кортежи (ключ, значение).
dan04

Да, вроде питона. :-) Я не знал, что KeyValuePair в C # не является кортежем?
Jubal

0

Это действительно полезно при возврате значений из функций. Мы можем вернуть несколько значений, и в некоторых сценариях это неплохо помогает.


0

Я наткнулся на этот тест производительности между кортежами и парами «ключ-значение», и, вероятно, вам это будет интересно. Таким образом, здесь говорится, что Tuple имеет преимущество, потому что это класс, поэтому он хранится в куче, а не в стеке, и при передаче в качестве аргумента его указатель - единственное, что происходит. Но KeyValuePair - это структуры, поэтому выделять их быстрее, но при использовании медленнее.

http://www.dotnetperls.com/tuple-keyvaluepair

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.