Когда полезно использовать ключевое слово C # ref?

Чем больше я вижу ref в используемом коде, тем больше я злоупотребляю им и тем больше это причиняет мне боль. Я стал ненавидеть это ключевое слово, потому что с точки зрения построения фреймворка это кажется глупым. Когда было бы неплохо сообщить пользователям вашего кода понятие , может быть изменить ссылку / значение объекта из-под них?

Напротив, Я люблю ключевые слова и люблю еще больше, когда они вообще не используются, в обоих случаях из-за гарантий, которые вы даете при их использовании. С другой стороны, ссылка не дает никаких гарантий, за исключением того, что вы будете вынуждены инициализировать параметр перед его передачей, даже если в нем ничего не изменится.

Хотя я не мудрый разработчик; Я уверен, что это имеет практически применимое использование. Я просто хотел бы знать, что они.

29
задан John Saunders 21 August 2010 в 23:07
поделиться

9 ответов

В Руководстве по проектированию каркаса (книга Кшиштофа Квалины и Брэда Абрамса) рекомендуется избегать обоих параметров 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 вместе.

33
ответ дан 28 November 2019 в 01:22
поделиться

Возможно, когда у вас есть структура (которая является типом значения):

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 .

2
ответ дан 28 November 2019 в 01:22
поделиться

Каждый раз, когда вы хотите изменить значение типа value - это часто происходит в тех случаях, когда вы хотите эффективно обновить пару связанных значений (т. Е. Вместо того, чтобы возвращать структуру, содержащую два int, вы передаете (ref int x, ref int y))

4
ответ дан 28 November 2019 в 01:22
поделиться

Большинство взаимосвязанных методов используют ref параметры по (я уверен, вы согласны) веской причине.

13
ответ дан 28 November 2019 в 01:22
поделиться

Я стараюсь избегать этого в общедоступных 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 - это частный метод, который был перемещен только для того, чтобы ответственность метода была управляемой.

10
ответ дан 28 November 2019 в 01:22
поделиться

Как насчет того, чтобы передать массив в функцию, которая может изменить или не изменить его размер и сделать с ним что-то еще. Часто массив оборачивают в другой объект, но если нужно работать с массивом напрямую, то передача по ссылке кажется наиболее естественным подходом.

0
ответ дан 28 November 2019 в 01:22
поделиться

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);
-1
ответ дан 28 November 2019 в 01:22
поделиться

Это полезно, когда вам нужны эффективные локальные алгоритмы для bignum.

0
ответ дан 28 November 2019 в 01:22
поделиться

Гипотетически, я предполагаю, что вы можете использовать множество аргументов ref / out, если вы намереваетесь имитировать архитектуру старого процедурного программного обеспечения, например старых игровых движков и так далее. Я просканировал исходный код одного, думаю, это был Duke Nukem 3D, и он процедурный, с множеством подпрограмм, изменяющих переменные на месте, и почти без функций. Очевидно, вы вряд ли запрограммируете подобное для реального производственного приложения, если у вас не будет какой-то конкретной цели.

0
ответ дан 28 November 2019 в 01:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: