Есть ли хорошее применение для параметров inout? - PullRequest
2 голосов
/ 27 февраля 2009

Есть ли хорошее применение для параметров inout (ref в C #, byref (как параметры out) в vb.net) в .NET?
Я чувствую, что путаница, вызванная параметром, используемым как в качестве входного, так и в качестве возвращаемого значения, хуже, чем увеличение количества параметров для параметров out, или возвращение массива или возвращение пользовательского класса.

Ответы [ 9 ]

6 голосов
/ 27 февраля 2009

Наиболее распространенное использование (которое все еще не так часто встречается, IMO), с которым я сталкивался, является своего рода «модификацией существующего объекта или созданием его при необходимости». Например:

public void AppendToBuilder(ref StringBuilder builder)
{
    if (builder == null)
    {
        builder = new StringBuilder();
    }
    builder.Append(/* whatever */);
}

StringBuilder, вероятно, не лучший пример, но это означает, что иногда вы можете избежать создания объекта, когда вам не нужно:

public static string DoSomething(IEnumerable<Foo> foos)
{
    // For an empty collection or where there aren't any
    // frobulating foos, we don't need to create a builder
    StringBuilder builder = null;
    foreach (Foo foo in foos)
    {
        if (foo.Frobulates)
        {
            foo.AppendToBuilder(ref builder);
        }
    }
    return builder == null ? null : builder.ToString();
}
5 голосов
/ 27 февраля 2009

Я использовал его в основном для адаптации к устаревшему коду. = (Com interop).

Я также склонен использовать его в коде, который должен быть быстродействующим и указывать на успех:

bool PerformSomeReadOperation(SomeInput obj, ref int defaultedOutput) { }

, где возвращаемое значение представляет собой понятие успеха или неудачи или, возможно, кода ошибки, а defaultedOutput является значением, которое входит в значение по умолчанию.

Знаете ли вы, что нет реальной разницы между out и ref (по крайней мере, что касается CLR)?

0 голосов
/ 28 февраля 2009

Вы действительно ответили на свой вопрос.

Если имеет смысл передавать данные как внутри, так и снаружи через параметр - т.е. если метод должен знать текущее значение и, как ожидается, обновит его (или, в случае ссылочного типа, заменит его), тогда ref является правильным. Это случается не часто, но когда это происходит, вы знаете, что использовать; -)

0 голосов
/ 28 февраля 2009

Я использую его, когда хочу изменить значение и считаю, что класс-оболочка является избыточным.

Например

if (line[index].StartsWith("X12"))
    ParseX12(lines, ref index, builder); //eats 2 or 4 lines

else if (line[index].StartsWith("A27"))
    ParseA27(lines, ref index, builder); //eats 1 line

else if (line[index].StartsWith("B16"))
    ParseB16(lines, ref index, builder); //eats 1 to 3 lines

else 
    index++; //this line couldn't be parsed, skip to the next one

В этом примере функции Parse могут занимать более одной строки. Таким образом, они несут ответственность за правильное обновление индексной переменной.

0 голосов
/ 27 февраля 2009

Out подходит для простых случаев, когда требуется несколько возвращаемых значений. Таким образом, вас не смущает «это параметр / это возвращаемое значение», которое может вызвать ref.

public void GetStockQuote(
  string stock, 
  out double lastTrade, 
  out DateTime tradeTime, 
  out double change, 
  out double open)
{
  //perform stock magic here
}
0 голосов
/ 27 февраля 2009

Я использовал его с параметром типа значения в графической подпрограмме, которая печатала текст в окне GDI в вертикальной компоновке. Параметр inout отслеживает текущую позицию Y:

WriteString("hello", ref y);

вместо

y += WriteString("hello", y);
0 голосов
/ 27 февраля 2009

Режимы передачи параметров и выхода используются для того, чтобы метод мог изменять переменные, передаваемые вызывающим методом.

Каждый режим передачи параметров (ref и out) предназначен для удовлетворения различных потребностей программирования.

Вызывающий метод, который принимает параметр out , равен , а не , необходимому для присвоения переменной, переданной в качестве параметра out до вызова; однако метод необходимо присвоить параметру out перед возвратом.

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

Не путайте концепцию передачи по ссылке с концепцией ссылочных типов.

Два понятия не связаны; параметр метода может быть изменен с помощью ref независимо от того, является ли это типом значения или ссылочным типом, при передаче по ссылке нет бокса с типом значения.

0 голосов
/ 27 февраля 2009

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

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

0 голосов
/ 27 февраля 2009

Когда вы, вероятно, совершите серию вызовов, которые изменяют одну и ту же переменную.

Хотя в языках на основе указателей, таких как C #, такого не бывает, потому что вы можете просто передать объект в качестве параметра «in», а вызываемая функция может вызывать свои методы для его изменения по мере необходимости.

...