Возвращаются два значения, Кортеж против 'из' против 'структура'
рассмотрим функцию, которая возвращает два значения. Мы можем написать:
// 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 ответов:
У каждого из них есть свои плюсы и минусы.
параметры Out быстры и дешевы, но требуют, чтобы вы передавали переменную и полагались на мутацию. Практически невозможно правильно использовать параметр out с LINQ.
кортежи делают коллекцию давления и являются самодокументирующимися. "Item1" не очень описателен.
пользовательские структуры может быть медленным, чтобы копировать, если они большие, но являются самодокументируемыми и эффективны, если они небольшие. Однако это также боль, чтобы определить целую кучу пользовательских структур для тривиального использования.
Я был бы склонен к решению пользовательской структуры при прочих равных условиях. Даже лучше, хотя это сделать функцию, которая возвращает только одно значение. Почему вы возвращаете два значения в первую очередь?
UPDATE: обратите внимание, что кортежи в C# 7, которые были отправлены через шесть лет после написания этой статьи, являются типами значений и, следовательно, с меньшей вероятностью создают давление сбора.
Я думаю, что ответ зависит от семантики того, что функция делает, и отношения между двумя значениями.
например,
TryParse
методы взятьout
параметр, чтобы принять анализируемое значение и вернуть abool
чтобы указать, удалось ли выполнить синтаксический анализ. Эти два значения на самом деле не принадлежат друг другу, поэтому семантически это имеет больше смысла, и намерение кода легче читать, использовать
добавляя к предыдущим ответам, 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()
Я пойду с подходом использования параметра Out, потому что во втором подходе вам потребуется создать и объект класса кортежа, а затем добавить к нему значение, которое, я думаю, является дорогостоящей операцией по сравнению с возвращением значения в параметре out. Хотя, если вы хотите вернуть несколько значений в классе кортежа (который не может быть выполнен, просто вернув один параметр out), то я пойду на второй подход.
вы не упомянули еще один вариант, который имеет пользовательский класс вместо структуры. Если данные имеют семантику, связанную с ними, которая может управляться функциями, или размер экземпляра достаточно велик (> 16 байт, как правило), пользовательский класс может быть предпочтительным. Использование "out" не рекомендуется в общедоступном API из-за его связи с указателями и требует понимания того, как ссылочные типы работа.
https://msdn.microsoft.com/en-us/library/ms182131.aspx
Кортеж хорош для внутреннего использования, но его использование неудобно в публичном API. Итак, мой голос находится между структурой и классом для публичного API.