Яку вимогу було розроблено для кортежу?


94

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

Для чого ви використовували кортежі у своїх програмах?

Оновлення

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

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

Потім використовуйте кортеж так:

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

Це правильно?



4
Ну, я можу придумати дві відповіді ...
Полудень Шовк

13
Якщо поняття "координата" має сенс як клас, то я б зробив це класом. Використовуйте кортежі для тих ситуацій, коли для набору даних не існує розумної концепції "ділової логіки", яка виправдовує створення типу.
Eric Lippert

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

8
Оскільки python це мав, а python не може мати нічого, чого у C # немає;)
Еван Плейс

Відповіді:


117

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

Багато мов програмування дозволяють логічно згрупувати набір не пов'язаних між собою значень, не створюючи тип лише одним способом:

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

Логічно, це точно так само, як метод M, який приймає один аргумент, який є 3-кортежем int, string, double. Але я сподіваюся, ви насправді не зробили б:

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

хіба що аргументи мали якесь інше значення в бізнес-логіці.

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

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

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


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

60
Хоча кортежі корисні, один великий недолік - це чіткість. Важко читати і розуміти код, який посилається на Item1, Item2тощо ... Якщо кортежі коли-небудь досягають мовної підтримки в C #, було б чудово дозволити їхнім членам називати (або принаймні псевдоніми) таким чином, що дозволяє код, який використовує їх бути зрозумілішими. У такому гіптетичному майбутньому я також хотів би бачити кортежі відповідної "форми" як юридичні параметри методів, які приймають окремі параметри (і навпаки). Отже, Tuple<int,string,bool>можна передати M(int,string,bool). Це значно полегшило б методи запам'ятовування.
Л.Бушкін

2
Ці "кортежі" в основному є анонімними типами з publicнеобмеженими членами . Я волів би, щоб програміст написав a з іменованими членами і повернув це, ніж мав справу з тим, що нічого не говорить мені про семантику своїх членів. structstructtuple
bobobobo

1
@ Hi-Angel: Аргумент стосується не суперечки щодо того, що вважається кортежем, а що ні, а навколо того, який набір функцій може використовувати сучасний розробник напряму бізнесу для підвищення своєї продуктивності . Л.Бушкін висловлює запит на функцію, який команда дизайнерів постійно чує: бажання зробити якийсь "тип запису", не вимагаючи витрат і витрат на створення цілого класу, щоб просто взяти разом кілька полів. C # вже має цю функцію для методів; це називається "список параметрів".
Ерік Ліпперт

2
@ Hi-Angel: Ви, мабуть, не стали б аргументувати "якщо ви хочете отримати доступ до параметрів методу за іменем, то вам слід створити окремий клас", оскільки це здається надзвичайно важким, але здається важким лише тому, що ми звикли мати можливість миттєво пов’язати набір довільних змінних з довільними типами та іменами при виклику методу . Уявіть, що жодна мова не мала такої особливості; кожен метод може приймати лише один аргумент, і якщо ви хочете передати два, вам доведеться створити тип і передати його екземпляр.
Ерік Ліпперт

22

Кортежі забезпечують незмінну реалізацію колекції

Окрім загального використання кортежів:

  • групувати спільні значення разом, не створюючи класу
  • повернути кілька значень із функції / методу
  • тощо ...

Незмінні об'єкти за своєю суттю є безпечними для потоків:

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

З «Незмінного об’єкта» на wikipedia


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

Якщо ви хочете незмінну колекцію, вам слід використовувати незмінювану колекцію, а не Кортеж. Різниця полягає в тому, що для більшості незмінних колекцій вам не потрібно вказувати кількість елементів під час компіляції
BlueRaja - Danny Pflughoeft

@ BlueRaja-DannyPflughoeft Ще коли я писав цю відповідь, незмінні класи колекції C # все ще були недоступні в BCL. Думаю, я зміню "колекцію" на "об'єкт", оскільки MS стерилізував реалізацію
Tuple

12

Він надає альтернативу refабо outякщо у вас є метод, який потребує повернення декількох нових об’єктів як частини його відповіді.

Це також дозволяє використовувати вбудований тип як тип повернення, якщо все, що вам потрібно зробити, - це збити два-три існуючих типи, і вам не потрібно додавати клас / структуру лише для цієї комбінації. (Коли-небудь хотілося, щоб функція могла повернути анонімний тип? Це часткова відповідь на цю ситуацію.)


Блін. Приємно. Я хотів би перевірити, що є кортежами кілька років тому;).
sabiland

10

Часто корисно мати тип "пара", який просто використовується у швидких ситуаціях (наприклад, повернення двох значень із методу). Кортежі є центральною частиною функціональних мов, таких як F #, і C # підхопив їх по ходу.




4

Особисто я вважаю, що Кортежі є ітеративною частиною розробки, коли ти перебуваєш у слідчому циклі або просто "граєш". Оскільки Tuple є загальним, я схильний думати про нього, працюючи із загальними параметрами - особливо коли хочу розробити загальний фрагмент коду, і я починаю з кінця коду, замість того, щоб запитати себе, "як би мені сподобався цей дзвінок дивитись?".

Досить часто я усвідомлюю, що колекція, яку формують Tuple, стає частиною списку, і, дивлячись на List> насправді не виражає наміру списку або того, як він працює. Я часто "живу" з цим, але виявляю, що хочу маніпулювати списком і змінити значення - в цей момент я не обов'язково хочу створювати для цього новий Tuple, тому мені потрібно створити власний клас або структуру щоб утримати його, щоб я міг додати маніпуляційний код.

Звичайно, завжди існують методи розширення - але досить часто ви не хочете поширювати цей додатковий код на загальні реалізації.

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

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

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

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

Якщо я отримаю можливість рефакторингу коду, то часто я буду ставити під сумнів місце Tuple в ньому.


3

Старе питання з 2010 року, а тепер у 2017 Dotnet змінюється і стає більш розумним.

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, але створення повного класу та об'єкта, що вміщує три ints, також здається досить важким.


1

Поширеним використанням може бути уникнення створення класів / структур, які містять лише 2 поля, замість цього ви створюєте Tuple (або KeyValuePair на даний момент). Корисно як повернене значення, уникайте передачі N параметрів ...


0

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


KeyValuePairможна розглядати як спеціальне обхідне рішення. У Python ітерація dictпросто повертає кортежі (ключ, значення).
dan04

Так, як python. :-) Я не знав, що KeyValuePair у c # не був кортежем?
Jubal

0

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


0

Я натрапив на цей показник ефективності між парами Tuples та Key-Value, і, мабуть, вам це буде цікаво. У підсумку сказано, що Tuple має перевагу, оскільки це клас, тому він зберігається в купі, а не в стеці, і коли його передають як аргумент, єдиним, що відбувається, є його вказівник. Але KeyValuePair є структурою, тому його швидше розподіляти, але він повільніший, коли використовується.

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

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