Чем больше я вижу ref в используемом коде, тем больше я злоупотребляю им и тем больше это причиняет мне боль. Я стал ненавидеть это ключевое слово, потому что с точки зрения построения фреймворка это кажется глупым. Когда было бы неплохо сообщить пользователям вашего кода понятие , может быть изменить ссылку / значение объекта из-под них?
Напротив, Я люблю ключевые слова и люблю еще больше, когда они вообще не используются, в обоих случаях из-за гарантий, которые вы даете при их использовании. С другой стороны, ссылка не дает никаких гарантий, за исключением того, что вы будете вынуждены инициализировать параметр перед его передачей, даже если в нем ничего не изменится.
Хотя я не мудрый разработчик; Я уверен, что это имеет практически применимое использование. Я просто хотел бы знать, что они.
В Руководстве по проектированию каркаса (книга Кшиштофа Квалины и Брэда Абрамса) рекомендуется избегать обоих параметров ref
и out
.
ИЗБЕГАЙТЕ параметров
out
илиref
.Использование параметров
out
илиref
требует опыта работы с указателями, понимания различий между типами значений и ссылочных типов и обработки методов с несколькими возвращаемыми значениями. Кроме того, не все понимают разницу между параметрамиout
иref
. Разработчики архитектуры инфраструктуры, проектирующие для широкой аудитории, не должны ожидать, что пользователи овладеют навыками работы с параметрамиout
илиref
.
В Руководстве по разработке фреймворка канонический метод Swap
упоминается как допустимое исключение:
void Swap<T>(ref T obj1, ref T obj2)
{
T temp = obj1;
obj1 = obj2;
obj2 = temp;
}
но в то же время в комментариях
Swap всегда упоминается в этих обсуждениях, но я не писал код, который действительно нуждался в методе подкачки еще со времен колледжа. Если у вас нет веской причины, избегайте
out
иref
вместе.
Возможно, когда у вас есть структура (которая является типом значения):
struct Foo
{
int i;
public void Test()
{
i++;
}
}
static void update(ref Foo foo)
{
foo.Test();
}
и
Foo b = new Foo();
update(ref b);
Здесь вы должны использовать два параметра с out
например:
static void update(Foo foo, out Foo outFoo) //Yes I know you could return one foo instead of a out but look below
{
foo.Test();
outFoo = foo;
}
визуализируя метод, имеющий более одного Foo
, тогда вы получите в два раза больше параметров с out
по сравнению с ref
. Альтернативой является возврат N-кортежа. У меня нет реального примера, когда использовать этот материал.
Дополнение: Различные .TryParse
методы также могли избежать out
, если бы они вернули вместо Nullable
, который по сути является кортежем логическое * T
.
Каждый раз, когда вы хотите изменить значение типа value - это часто происходит в тех случаях, когда вы хотите эффективно обновить пару связанных значений (т. Е. Вместо того, чтобы возвращать структуру, содержащую два int, вы передаете (ref int x, ref int y))
Большинство взаимосвязанных
методов используют ref
параметры по (я уверен, вы согласны) веской причине.
Я стараюсь избегать этого в общедоступных API, но он определенно находит применение. Изменяемые типы значений важны, особенно для таких вещей, как CF (где изменяемые структуры более распространены из-за требований платформы). Однако, пожалуй, чаще всего я использую его при рефакторинге частей сложного алгоритма на несколько методов, когда объект состояния избыточен, и мне нужно передать несколько значений:
т.е.
var x = .....
var y = .....
// some local code...
var z = DoSomethingSpecific(ref x, ref y); // needs and updates x/y
// more local code...
и др. Где DoSomethingSpecific
- это частный метод, который был перемещен только для того, чтобы ответственность метода была управляемой.
Как насчет того, чтобы передать массив в функцию, которая может изменить или не изменить его размер и сделать с ним что-то еще. Часто массив оборачивают в другой объект, но если нужно работать с массивом напрямую, то передача по ссылке кажется наиболее естественным подходом.
I ' m довольно часто используют ref. Просто подумайте о функциях с несколькими возвращаемыми значениями. Нет смысла создавать возвращаемый объект (вспомогательный объект) или даже использовать для этой цели хэш-таблицы.
Пример:
getTreeNodeValues(ref selectedValue, ref selectedText);
Изменить:
Лучше использовать здесь - как прокомментировано.
getTreeNodeValues(out selectedValue, out selectedText);
Я использую его для обработки объектов:
MyCar car = new MyCar { Name="TestCar"; Wieght=1000; }
UpdateWeight(ref car, 2000);
Это полезно, когда вам нужны эффективные локальные алгоритмы для bignum.
Гипотетически, я предполагаю, что вы можете использовать множество аргументов ref / out, если вы намереваетесь имитировать архитектуру старого процедурного программного обеспечения, например старых игровых движков и так далее. Я просканировал исходный код одного, думаю, это был Duke Nukem 3D, и он процедурный, с множеством подпрограмм, изменяющих переменные на месте, и почти без функций. Очевидно, вы вряд ли запрограммируете подобное для реального производственного приложения, если у вас не будет какой-то конкретной цели.