【问题标题】:When does a param that is passed by reference get updated?通过引用传递的参数何时更新?
【发布时间】:2010-06-30 22:03:49
【问题描述】:

假设我有这样的方法:

public void MyCoolMethod(ref bool scannerEnabled)
{
    try
    {
        CallDangerousMethod();


    } 
    catch (FormatException exp)
    {
        try
        {
            //Disable scanner before validation.
            scannerEnabled = false;

            if (exp.Message == "FormatException")
            {
                MessageBox.Show(exp.Message);
            }
        }
        finally
        {
            //Enable scanner after validation.
            scannerEnabled = true;
        }
    }

它是这样使用的:

    MyCoolMethod(ref MyScannerEnabledVar);

扫描器可以随时在单独的线程上触发。如果我们正在处理异常,我们的想法是不要让它发生。

我的问题是,对 MyCoolMethod 的调用是在设置 scannerEnabled 时更新 MyScannerEnabledVar 还是在方法退出时更新它?

注意:这段代码不是我写的,我只是想安全地重构它。

【问题讨论】:

  • 我认为你在重构这个是正确的。
  • 您可能想要查看互斥锁。它们就是为此目的而设计的。

标签: c# reference parameter-passing


【解决方案1】:

您可以将 ref 视为为变量创建别名。并不是你传递的变量是“引用传递”,而是参数和实参是同一个变量,只是名字不同而已。所以更新一个会立即更新另一个,因为一开始这里实际上并没有两件事。

正如 SLaks 所指出的,在 VB 中存在使用复制输入复制输出语义的情况。如果我没记错的话,还有一些罕见且晦涩的情况,其中表达式树可能被编译为执行复制输入复制输出的代码,但我不记得细节了。

如果此代码旨在更新变量以在另一个线程上读取,则变量“立即”更新的事实具有误导性。请记住,在多个线程上,如果读取和写入不是易失性的,则可以观察到读取和写入相对于彼此在时间上向前和向后移动。如果打算将变量用作跨线程通信机制,则他们使用实际设计 用于该目的的对象,该对象对于该目的是安全。使用某种等待句柄或互斥锁等。

【讨论】:

  • 这又如何:private readonly object syncLock = new object(); private object _value; public void Set(object value) => handleSet(ref _value, value); private void handleSet(ref member, object value) { lock (syncLock) member = value; } 那个 setter 线程安全吗? --- ref 成员在锁定之前不会被取消引用?? (即 Set() 方法不锁定锁并传递一个 ref;但直到 handleSet 方法才真正写入 ref --- 并且在锁之下。)
  • 类似:public object Get => handleGet(ref _value); private object handleGet(ref member) { lock (syncLock) return member; }
【解决方案2】:

它会实时更新,因为它是在方法内部分配的。

当您通过引用传递参数时,运行时传递(等效于)指向您引用的字段或变量的指针。当方法分配给参数时,它直接分配给引用指向的任何东西。

请注意,在 VB 中并非总是如此。

【讨论】:

  • 是的,它会在您执行 var = somenewvalue; 的毫秒数发生变化;
【解决方案3】:

是的,它会在方法中设置变量时设置。也许最好返回 true 或 false 是否启用扫描仪,而不是将其作为 ref arg 传入

【讨论】:

    【解决方案4】:

    这种情况需要的不仅仅是简单的重构。您发布的代码将受到竞争条件的约束。简单的解决方案是锁定不安全的方法,从而迫使线程跳线。事实上,由于这段代码,应用程序中肯定会出现一些错误,但如果不了解更多关于您的要求和实现的信息,就不可能说出它们到底是什么。我建议您谨慎行事,互斥锁/锁是一种简单的修复方法,但可能会对性能产生很大影响。如果您对此感到担忧,那么你们都应该查看更好的线程安全解决方案。

    【讨论】:

      猜你喜欢
      • 2010-09-13
      • 2010-10-07
      • 1970-01-01
      • 1970-01-01
      • 2011-08-21
      • 1970-01-01
      • 2012-04-21
      • 2017-09-25
      • 1970-01-01
      相关资源
      最近更新 更多