Подтвердить что ты не робот

Когда используется ключевое слово С# ref всегда хорошая идея?

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

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

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

4b9b3361

Ответ 1

Руководство по дизайну Framework (книга Кшиштофа Квалины и Брэда Абрамса) рекомендует избегать параметров ref и out.

ИЗБЕГАЙТЕ с помощью параметров out или ref.

Использование параметров out или ref требует опыта работы с указателями, понимания того, как различаются типы значений и ссылочные типы, а также методы обработки с несколькими возвращаемыми значениями. Кроме того, разница между параметрами out и ref не получила широкого распространения. Проектирование рамочных архитекторов для широкой аудитории не должно ожидать, что пользователи освоят работу с параметрами out или ref.

В Руководстве по дизайну Framework цитируется канонический метод Swap как допустимое исключение:

void Swap<T>(ref T obj1, ref T obj2)
{
    T temp = obj1;
    obj1 = obj2;
    obj2 = temp;
}

но в то же время комментарий замечает

В этих обсуждениях всегда появляется своп, но я не написал код, который на самом деле нуждался в методе свопа после колледжа. Если у вас нет веской причины, избегайте out и ref вообще.

Ответ 2

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

Ответ 3

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

Ответ 4

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

Ответ 5

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

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> вместо этого, который по существу является кортежем boolean * T.

Ответ 6

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

Ответ 7

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

Ответ 8

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

Ответ 9

Другим полезным примером в дополнение к swap < > является следующее:

Prompter.getString("Name ? ", ref firstName);
Prompter.getString("Lastname ? ", ref lastName);
Prompter.getString("Birthday ? ", ref firstName);
Prompter.getInt("Id ? ", ref id);
Prompter.getChar("Id type: <n = national id, p = passport, d = driver licence, m = medicare> \n? ", ref c);



public static class Prompter
{
    public static void getKey(string msg, ref string key)
    {
        Console.Write(msg);
        ConsoleKeyInfo cki = Console.ReadKey();
        string k = cki.Key.ToString();
        if (k.Length == 1)
            key = k;
    }

    public static void getChar(string msg, ref char key)
    {
        Console.Write(msg);
        key = Console.ReadKey().KeyChar;
        Console.WriteLine();
    }

    public static void getString(string msg, ref string s)
    {
        Console.Write(msg);
        string input = Console.ReadLine();
        if (input.Length != 0)
            s = input;
    }

    public static void getInt(string msg, ref int i)
    {
        int result;
        string s;

        Console.Write(msg);
        s = Console.ReadLine();

        int.TryParse(s, out result);
        if (result != 0)
            i = result;       
    }

    // not implemented yet
    public static string getDate(string msg)
    {
        // I should use DateTime.ParseExact(dateString, format, provider);
        throw new NotImplementedException();
    }    


}

Используйте здесь это не вариант

Ответ 10

Я использую ref довольно часто. Просто подумайте о функциях с несколькими возвращаемыми значениями. Не имеет смысла создавать объект возврата (вспомогательный объект) или даже использовать хеш-таблицы для этой цели.

Пример:

 getTreeNodeValues(ref selectedValue, ref selectedText);

Edit:

Лучше использовать здесь - как прокомментировано.

 getTreeNodeValues(out selectedValue, out selectedText);

Я использую его для обработки объектов:

MyCar car = new MyCar { Name="TestCar"; Wieght=1000; }

UpdateWeight(ref car, 2000);