C# 为什么要将发送方闭包与PipeTo()一起使用?

C# 为什么要将发送方闭包与PipeTo()一起使用?,c#,akka,akka.net,C#,Akka,Akka.net,下面是在Akka.NET中使用PipeTo()的示例: Receive<BeginProcessFeed>(feed => { //instance variable for closure var senderClosure = Sender; SendMessage(string.Format("Downloading {0} for RSS/ATOM processing...", feed.FeedUri)); //reply bac

下面是在Akka.NET中使用
PipeTo()
的示例:

Receive<BeginProcessFeed>(feed =>
{
    //instance variable for closure
    var senderClosure = Sender; 
    SendMessage(string.Format("Downloading {0} for RSS/ATOM processing...", feed.FeedUri));

    //reply back to the sender
    _feedFactory.CreateFeedAsync(feed.FeedUri).PipeTo(senderClosure);
});
在这个示例和文档中,都说这里必须使用闭包。但我不认为有任何理由这样做

如果我们使用了
ContinueWith()
,那么在continuation中使用闭包是合理的,但不能作为
PipeTo()
参数


我错过了什么吗?

这里有两件事需要理解:

  • Sender
    不是静态属性。返回正在处理的当前邮件的发件人。每次上下文从邮箱获取新邮件时,返回的值都会更改

  • PipeTo
    是一个延续,当该延续在线程池上执行时,调用
    Sender
    将访问与启动任务完全相同的
    IActorContext
    对象。无法保证上下文中当前的
    发送方
    是相同的,因为自任务启动后,新消息被推送到参与者中进行处理


  • 因此,我们将
    Sender
    的值缓存在一个局部变量中,以确保无论何时执行
    PipeTo
    时,我们的目标都是正确的
    iactoref

    当编译器在闭包上下文中捕获“this”时,就会出现您描述的问题。例如,当我们在lambda表达式中使用“this”成员(如Sender)时,就会发生这种情况。但在这里,我们只是将参数传递给PipeTo()方法,并且没有创建闭包。Sender是一个上下文敏感的方法—每次参与者收到消息时,它的值都会发生变化。如果Sender的当前值未缓存在局部变量中(使用PipeTo时会关闭),则很有可能Sender调用返回的值与预期的参与者不同。我们已经多次重复此错误:p@Aaronontheweb:“如果发送方的当前值未缓存在局部变量中,则使用PipeTo时会关闭该局部变量”。这对我来说没有意义:PipeTo所做的不是关闭
    发送方
    属性,而是关闭一个局部变量(参数
    接收方
    ),该变量是当前
    发送方
    引用的副本。因此,我认为这与将
    Sender
    属性显式复制到局部变量没有什么不同。@AndrewS。再挖深一点。发送方是静态的,因为它是静态属性的成员。Sender是一个属性,它返回受保护的IActorRef Sender=>Context.Sender;。看看上下文。它受静态上下文保护。继续挖掘,您最终将获得[ThreadStatic]私有静态ActorCell\u current;Petabridge现场PipeTo的官方例子是关于关闭的错误。这根本不是闭包的例子,而是参数传递的例子。仔细阅读结束语。所讨论的变量必须是自由变量。不是参数。您可以轻松地将发送方直接发送到PipeTo,因为它会立即被调用,并与CreateFeedAsync并行运行。别相信我。你自己试试看。
    _feedFactory.CreateFeedAsync(feed.FeedUri).PipeTo(Sender);