Возвращая два значения, Tuple vs 'out' vs 'struct' - PullRequest
73 голосов
/ 17 июня 2011

Рассмотрим функцию, которая возвращает два значения. Мы можем написать:

// Using out:
string MyFunction(string input, out int count)

// Using Tuple class:
Tuple<string, int> MyFunction(string input)

// Using struct:
MyStruct MyFunction(string input)

Какая из них является наилучшей и почему?

Ответы [ 6 ]

83 голосов
/ 17 июня 2011

У каждого из них есть свои плюсы и минусы.

Выходные параметры бывают быстрыми и дешевыми, но требуют, чтобы вы передали переменную и полагались на мутацию.С LINQ почти невозможно правильно использовать параметр out.

Кортежи создают давление сбора и не документируют себя.«Item1» не очень описательный.

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

Я бы склонялся к решению с пользовательской структурой при прочих равных условиях.Еще лучше, если сделать функцию, которая возвращает только одно значение .Почему вы возвращаете два значения в первую очередь?

ОБНОВЛЕНИЕ: обратите внимание, что кортежи в C # 7, поставленные через шесть лет после написания этой статьи, являются типами значений и, следовательно, с меньшей вероятностью создают давление при сборе.

19 голосов
/ 17 июня 2011

Я думаю, что ответ зависит от семантики того, что делает функция, и от отношения между двумя значениями.

Например, методы TryParse принимают параметр out для принятия проанализированногозначение и верните bool, чтобы указать, успешно ли выполнен анализ.Два значения на самом деле не принадлежат друг другу, так что семантически это имеет больше смысла, и смысл кода легче читать, используя параметр out.

Если, однако, ваша функциявозвращает координаты X / Y какого-либо объекта на экране, затем два значения семантически принадлежат друг другу, и было бы лучше использовать struct.

. Я бы лично избегал использования tuple для всего, чтобудет виден внешнему коду из-за неудобного синтаксиса для извлечения членов.

15 голосов
/ 06 июня 2017

Добавляя к предыдущим ответам, C # 7 приносит кортежи типа значения, в отличие от System.Tuple, который является ссылочным типом и также предлагает улучшенную семантику.

Вы все еще можете оставить их без имени и использовать синтаксис .Item*:

(string, string, int) getPerson()
{
    return ("John", "Doe", 42);
}

var person = getPerson();
person.Item1; //John
person.Item2; //Doe
person.Item3;   //42

Но что действительно важно в этой новой функции, так это возможность именовать кортежи.Таким образом, мы могли бы переписать вышеупомянутое как это:

(string FirstName, string LastName, int Age) getPerson()
{
    return ("John", "Doe", 42);
}

var person = getPerson();
person.FirstName; //John
person.LastName; //Doe
person.Age;   //42

Разрушение также поддерживается:

(string firstName, string lastName, int age) = getPerson()

1 голос
/ 31 августа 2016

Вы не упомянули еще одну опцию, которая имеет собственный класс вместо struct.Если с данными связана семантика, с которой могут работать функции, или размер экземпляра достаточно велик (как правило,> 16 байт), предпочтительным может быть пользовательский класс.Использование «out» не рекомендуется в общедоступном API из-за его связи с указателями и необходимости понимания того, как работают ссылочные типы.

https://msdn.microsoft.com/en-us/library/ms182131.aspx

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

1 голос
/ 17 июня 2011

Я пойду с подходом использования параметра Out, потому что при втором подходе вам потребуется создать объект класса Tuple, а затем добавить к нему значение, что, на мой взгляд, является дорогостоящей операцией по сравнению с возвратом значения в параметре out. Хотя, если вы хотите вернуть несколько значений в классе кортежей (что невозможно сделать, просто вернув один выходной параметр), я перейду ко второму подходу.

0 голосов
/ 17 июня 2011

Нет «лучшей практики».Это то, что вам удобно и что лучше всего работает в вашей ситуации.Если вы согласны с этим, у вас не возникнет проблем ни с одним из опубликованных вами решений.

...