【问题标题】:How to pass a ref parameter inside lambda expression? - Thread issue如何在 lambda 表达式中传递 ref 参数? - 线程问题
【发布时间】:2014-05-05 15:43:52
【问题描述】:

我有一个方法要调用。

public void RecordConversation(ref ChannelResource cr)
{
    VoiceResource RecordResource = TServer.GetVoiceResource();
    RecordResource.MaximumTime = 6000;
    RecordResource.MaximumSilence = 6000;
    RecordResource.TerminationDigits = "";
}

在线程中调用它

Thread recordThread = new Thread(() => RecordConversation(ref ChanResource));
recordThread.Start();

我们当然会得到一个错误。

不能在匿名方法、lambda 表达式或查询表达式中使用 ref 或 out 参数“ChanResource”

如何解决?

【问题讨论】:

标签: c# multithreading lambda ref


【解决方案1】:

为什么会出现这个错误?

匿名方法的参数范围 匿名方法块

(强调我的)

lambda 表达式本质上与匿名方法相同。

根据文档,参数的范围仅限于其块。

但是refout 不在范围内,因此会出现错误。我建议你不要使用ref,因为参数默认是按值传递的,如果是引用类型,reference的值会被传递。 p>

您可以直接修改参数以反映该更改。

【讨论】:

  • 参考 +1
  • @spender,是的。强调
【解决方案2】:

您不能使用ref。见this very same question

话虽如此,你提到的原因(对象很大,经常使用,我不想在值类型中传递它)是无效的。

如果您删除 ref,您将不会将参数作为值传递。在这里使用ref 不会有任何性能/内存增益。 见value vs reference

【讨论】:

  • 但是我很困惑,如果对象被使用了 10 次,我们将它的值传递了 10 次。有内存问题吗?
  • @Love 没有任何内存问题。如果没有ref,将会发生的是对象的reference 将作为值传递,而不是对象本身。
  • --@ken2k,我使用来自stackoverflow.com/questions/4986341/… 的答案的 ref ifs 的原因。 2.如果您调用的函数需要将大对象作为参数,请通过 const 引用传递它,以避免对该对象进行不必要的复制并降低效率。
  • @Love 这是一个 C++ 答案。 C++ 和 .Net (C#) 之间的内存管理方式非常非常不同。
  • @Love 请记住,“副本”仅在函数范围内存在于内存中。一旦函数完成,副本就会被销毁并返回到内存中。
【解决方案3】:

改为:

Thread recordThread = new Thread(() => RecordConversation(ref ChanResource));
recordThread.Start();

你应该这样做:

Thread recordThread = new Thread(() => {
    VoiceResource RecordResource = TServer.GetVoiceResource();
    RecordResource.MaximumTime = 6000;
    RecordResource.MaximumSilence = 6000;
    RecordResource.TerminationDigits = "";
});
recordThread.Start();

【讨论】:

    【解决方案4】:

    如果您没有在方法中重新创建它,则不必将此对象作为引用传递。但是,如果您要重新创建它,那么您的 ref 将是有意义的:

    public void RecordConversation(ref ChannelResource cr)
    {
        cr = new ChannelResource();
        VoiceResource RecordResource = TServer.GetVoiceResource();
        RecordResource.MaximumTime = 6000;
        RecordResource.MaximumSilence = 6000;
        RecordResource.TerminationDigits = "";
    }
    

    通过 ref 创建一个对象会导致调用者被创建为一个新对象。

    由于闭包环境,您不能在 lambda 表达式中发送 ref。 C# 在运行时编译匿名表达式。如果您尝试将 ref 发送到您的封闭代码,那么编译器必须找到一种方法来访问您的 ref 对象,这没有任何意义。您可以在这里查看关闭情况:http://en.wikipedia.org/wiki/Closure_(computer_science)

    【讨论】:

      【解决方案5】:
      public class ThreadParams
      {
          public ChannelResource ChanResource;
          public ThreadParams(ChannelResource chanResource) {
              ChanResource = chanResource; }
      }
      
      public void ThreadProc(Object obj)
      {
          RecordConversation(ref ((ThreadParams)obj).ChanResource);
      }
      
      Thread recordThread = new Thread(ThreadProc);
      recordThread.Start(new ThreadParams(ChanResource));
      

      唯一的问题是您的程序现在编辑传递对象中的字段,而不是实际变量,因此您必须检查该字段。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-03-25
        • 1970-01-01
        • 1970-01-01
        • 2013-01-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多