Рассмотрим функцию, которая возвращает два значения. Мы можем написать:
// Using out:
string MyFunction(string input, out int count)
// Using Tuple class:
Tuple<string, int> MyFunction(string input)
// Using struct:
MyStruct MyFunction(string input)
Какой из них является лучшим и почему?
struct
какEric
упоминались.Ответы:
У каждого из них есть свои плюсы и минусы.
Параметры Out являются быстрыми и дешевыми, но требуют, чтобы вы передавали переменную и полагались на мутацию. Практически невозможно правильно использовать выходной параметр с LINQ.
Кортежи создают давление при сборке мусора и не являются самодокументированными. "Item1" не очень информативен.
Пользовательские структуры могут медленно копироваться, если они большие, но они самодокументируются и эффективны, если они маленькие. Однако также сложно определить целую кучу настраиваемых структур для тривиального использования.
Я был бы склонен к индивидуальному структурному решению при прочих равных условиях. Еще лучше создать функцию, которая возвращает только одно значение . Почему вы вообще возвращаете два значения?
ОБНОВЛЕНИЕ: обратите внимание, что кортежи в C # 7, которые были выпущены через шесть лет после написания этой статьи, являются типами значений и, следовательно, с меньшей вероятностью будут создавать давление сбора.
источник
В дополнение к предыдущим ответам 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()
источник
Я думаю, что ответ зависит от семантики того, что делает функция, и отношения между двумя значениями.
Например,
TryParse
методы принимаютout
параметр, чтобы принять проанализированное значение, и возвращают,bool
чтобы указать, был ли синтаксический анализ успешным. Эти два значения на самом деле не принадлежат друг другу, поэтому семантически это имеет больше смысла, а цель кода легче читать, чтобы использоватьout
параметр.Если, однако, ваша функция возвращает координаты X / Y некоторого объекта на экране, тогда два значения семантически принадлежат друг другу, и было бы лучше использовать
struct
.Лично я бы избегал использовать a
tuple
для всего, что будет видно внешнему коду из-за неудобного синтаксиса для получения членов.источник
out
параметрnull
. Есть несколько неизменяемых типов, допускающих значение NULL.try
шаблон , который работает с ковариант- интерфейсамиT TryGetValue(whatever, out bool success)
; такой подход позволил бы интерфейсыIReadableMap<in TKey, out TValue> : IReadableMap<out TValue>
и позволить коду, который хочет сопоставить экземплярыAnimal
с экземплярами,Car
принятьDictionary<Cat, ToyotaCar>
[usingTryGetValue<TKey>(TKey key, out bool success)
. Такая дисперсия невозможна, еслиTValue
используется в качествеref
параметра.Я буду использовать подход с использованием параметра Out, потому что во втором подходе вам потребуется создать объект класса Tuple, а затем добавить к нему значение, что, на мой взгляд, является дорогостоящей операцией по сравнению с возвратом значения в параметре out. Хотя, если вы хотите вернуть несколько значений в классе кортежей (что на самом деле не может быть достигнуто путем простого возврата одного параметра), я выберу второй подход.
источник
out
. Кроме того, естьparams
ключевое слово, которое я не упомянул, чтобы задать вопрос.Вы не упомянули еще один вариант, который имеет собственный класс вместо структуры. Если данные имеют связанную с ними семантику, с которой могут работать функции, или если размер экземпляра достаточно велик (как правило,> 16 байт), предпочтительным может быть специальный класс. Использование out не рекомендуется в общедоступном API, поскольку оно связано с указателями и требует понимания того, как работают ссылочные типы.
https://msdn.microsoft.com/en-us/library/ms182131.aspx
Кортеж хорош для внутреннего использования, но неудобно использовать его в общедоступном API. Итак, я голосую между структурой и классом публичного API.
источник
Не существует «лучшей практики». Это то, что вам удобно и что лучше всего работает в вашей ситуации. Пока вы согласны с этим, нет никаких проблем ни с одним из опубликованных вами решений.
источник