【问题标题】:Is there a good reason to ever pass a ref string or ref class to a function?是否有充分的理由将 ref 字符串或 ref 类传递给函数?
【发布时间】:2010-11-16 20:55:24
【问题描述】:

今天我和一位同事正在讨论制作这种功能是否有用:

private void MyFunction(ref MyClass variable)
    {

    }

我能看到的唯一优点是它允许您将指向变量的原始指针设置为 null...除此之外,如果您省略了 ref 将没有区别,对吗?

你能想出任何理由将 ref 字符串传递给函数吗?

【问题讨论】:

标签: c# .net


【解决方案1】:

就我个人而言,我更愿意返回具有多个值的Tuple,但基本点是向调用者提供多个结果。在 ref 参数的情况下,额外的结果可能会替换现有变量中的值。请注意,这与仅处理参数本身非常不同。例如:

public void Foo(ref StringBuilder builder)
{
    builder = new StringBuilder("hello");
}

完全不同于:

public void Foo(StringBuilder builder)
{
    builder.Clear();
    build.Append("hello");
}

参数类型是引用类型还是值类型在某种程度上无关紧要 - 特别是当您考虑不可变类型时,例如 string,其中没有与上述后一种方法等效的方法。 p>

【讨论】:

  • 我就是这么做的——返回Tuple。主要原因是如果我开始传递refout 参数,有些人可能不明白我的代码在做什么。参数输入,返回值输出 - 我尽量保持这种状态。
  • 返回元组肯定是“out”参数的替代方案,而不是“ref”参数。很少需要“ref”参数,但是当它们需要时(例如 Interlocked.Exchange),返回元组不是替代品。
【解决方案2】:

TryParseTryGetValue 系列方法?

获取一个值和一个成功的指示,而无需解析/搜索两次。

我自己使用它来拆分和地址为街道和门牌号。在我两者都有的方法中,如果我只有一个返回值,我将不得不将数据拆分两次。

您使用的示例看起来没什么用,除非在互操作上下文中。

【讨论】:

  • TryParse 和 TryGetValue 不使用 ref 他们使用 out 这在这个问题的上下文中是不同的。
【解决方案3】:

这是一个简短的例子。

private void MyFunction(ref MyClass variable)
{
  variable = new MyClass();
  // You just changed the variable that was passed,
  // even outside the scope of this method!
}

private void MyFunction(MyClass variable)
{
  variable = new MyClass();
  // Without ref, the variable is still intact
  // outside of this scope.
}

【讨论】:

  • 这绝对回答了 OP 的问题。但是拜托,看在上帝的份上,如果你需要这样做,只需要返回类型为“MyClass”
  • @viggity 但是你需要写myClassVar = MyFuction(myClassVar) 而不仅仅是MyFunction(myClassVar)
  • 是的,但它会更容易阅读和维护。我不喜欢调用一个修改状态开始的方法,但是在不让调用者明确知道的情况下交换整个引用是自找麻烦。
【解决方案4】:

有时你想同时返回一个值并更新一个对象:

// Converts specified brush to grayscale. Returns `true` on success,
// or `false` if the brush is already grayscale.
public bool MakeBrushGrayscale(ref SolidBrush brush)
{
    if (IsGrayscale(brush.Color)) {
        return false;
    }

    brush = new SolidBrush(GetGrayscaleColor(brush.Color));
    return true;
}

【讨论】:

  • 虽然在这种情况下您可能需要一个 out 参数,或者您想在创建新画笔之前处理掉画笔,但无需泄漏句柄 :)
  • @pstrjds, out 参数可能未初始化,这会破坏函数的第一行。 Dispose() 是对的,但我想我会让 GC 来处理这个例子:)
  • 好调用out参数,应该想通了。我对 System.Drawing 空间中的 Brushes 和其他对象感到偏执,因为 GDI 句柄泄漏而导致程序崩溃,所以我想确保在这些对象上调用 Dispose。当有人可能想要使用 ref 参数以便修改传入的对象时,这仍然是一个可靠的示例。一定要喜欢副作用!
【解决方案5】:

有时您可能想要更改对象引用。想象一个名为 Reload(object o) 的方法,它用数据库中的数据重新加载一个对象。您可以从数据访问层获取对象的新实例(与原始引用不同 - 它不支持身份映射)并需要将其返回给用户。

你有两个选择:

object Reload(object o)
{
    return dao.GetById(IdHelper.GetId(o));
}

void Reload(ref object o)
{
    o = dao.GetById(IdHelper.GetId(o));
}

有些人可能会认为前者是更好的设计。但是,它有一个问题。使用它的开发人员可能会忘记将返回值分配给变量,以为传递给方法的对象将被更改。 ref 属性使得无法错误地使用第二种方法版本。

【讨论】:

    【解决方案6】:

    我不能说这是一个很好的理由,但是如果您要固定它并操纵字符串的原始数据(也许您的函数将其传递给某种交换字符的加密方法)。

    【讨论】:

      【解决方案7】:

      我认为到处使用 ref 是不好的做法。

      1. 良好的做法是不要给超出必要的范围。
      2. 使用 ref 时,不能将 null 传递给方法。

      【讨论】:

        猜你喜欢
        • 2011-08-30
        • 2011-08-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-21
        • 2012-07-29
        • 2020-02-17
        • 2012-11-19
        相关资源
        最近更新 更多