2

.NET 中的 inout(C# 中的 ref,vb.net 中的 byref(如 out 参数))参数有很好的用途吗?
我觉得一个参数既作为输入又作为返回值造成的混乱,比out参数的参数数量增加,或者返回数组或者返回自定义类更糟糕。

4

9 回答 9

6

我遇到的最常见的用途(仍然不是那么常见,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();
}
于 2009-02-27T20:41:00.203 回答
5

我主要用它来适应遗留代码。=(com互操作)。

我也倾向于在需要高性能并表明成功的代码中使用它:

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

其中返回值是成功或失败的概念,或者可能是错误代码,而 defaultedOutput 是带有默认值的值。

您是否知道out 和 ref 之间没有真正的区别(至少就 CLR 而言)?

于 2009-02-27T20:48:16.923 回答
0

当您可能进行一系列修改同一变量的调用时。

但是,在 C# 等基于指针的语言中,这种情况不会发生太多,因为您可以将对象作为“in”参数传递,并且被调用的函数可以调用其方法来根据需要对其进行修改。

于 2009-02-27T20:33:06.773 回答
0

在极少数情况下,它可能很有用,主要是出于性能原因。

在大多数情况下,它可以并且在我看来应该通过返回您提到的数组或自定义类来避免。

于 2009-02-27T20:35:03.243 回答
0

ref 和 out 参数传递模式用于允许方法更改由方法调用者传入的变量。

每种参数传递模式(ref 和 out)都旨在适应不同的编程需求。

带有out 参数的方法的调用者不需要在调用之前分配作为 out 参数传递的变量;但是,该方法需要在返回之前分配给 out 参数。

一种考虑out参数的方法是,它们就像方法的附加返回值。当一个方法应该返回多个值时,它们很方便。

不要将通过引用传递的概念与引用类型的概念混淆。

这两个概念不相关;方法参数无论是值类型还是引用类型都可以被ref修改,通过引用传递时没有值类型的装箱。

于 2009-02-27T20:39:17.057 回答
0

我在图形例程中将它与值类型参数一起使用,该例程以垂直布局将文本打印到 GDI 窗口。inout 参数跟踪当前的 Y 位置:

WriteString("hello", ref y);

而不是

y += WriteString("hello", y);
于 2009-02-27T20:45:33.607 回答
0

Out 适用于需要多个返回值的简单情况。这样您就不ref会对可能导致的“它是参数/它是返回值”感到困惑。

public void GetStockQuote(
  string stock, 
  out double lastTrade, 
  out DateTime tradeTime, 
  out double change, 
  out double open)
{
  //perform stock magic here
}
于 2009-02-27T20:46:26.680 回答
0

当我想修改一个值并认为包装类太过分时,我会使用它。

例如

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 函数可能会消耗不止一行。因此,他们负责正确更新索引变量。

于 2009-02-27T22:11:10.313 回答
0

你真的回答了你自己的问题。

如果通过参数传入和传出数据是有意义的 - 即。如果该方法需要知道当前值并且还需要更新它(或者,在引用类型的情况下,替换它),那么 ref 是正确的。它不会经常发生,但是当它发生时,您知道该使用什么;-)

于 2009-02-28T00:14:33.700 回答