什么使对象不被处理?/是否异步流保持对象存活

本文关键字:对象 异步 是否 处理 什么 | 更新日期: 2023-09-27 18:16:16

考虑以下代码:

public class ChainHandler
{
    public void ProcessTopUp(string amount, string phone, ResponseCallback responseCallback)
    {
        var statebag = GetStateBag();
        ICommand basecommand = new BlmLoginCommand(statebag);
        basecommand .SetNext(new BlmDynamicCommand(statebag, RequestMessageEvent.TCD_RecargaTAE10, new Dictionary<string, string> { { "amt", amount }, { "cel", phone } }))
               .SetNext(new BlmDynamicCommand(statebag, RequestMessageEvent.TCD_BuyProduct))
               .SetNext(new BlmEndCommand(statebag, responseCallback));
        basecommand.ExecuteAsync();
    }

}
class Program
{
    static void Main(string[] args)
    {
        ChainHandler ch = new ChainHandler();
        ch.ProcessTopUp("5.00", "0123456789", OnProcessResponse);
        Console.ReadLine();
    }
    private static void OnProcessResponse()
    {
        //...
    }
}

方法"ExecuteAsync"启动一个使用命令的异步流。在Socket类内部异步使用的命令(基于事件的异步模式)。

问题是:是否有可能,EndCommand是永远不会达到,因为对象基础命令得到处置后离开"ExecuteAsync"方法?

甚至。net都知道EndCommand有一个回调方法?

或者。net是否足够智能,可以让对象保持活动状态,直到异步流完成?

如果对象不保持活,我能做些什么来指示垃圾收集器不处理基本命令?

什么使对象不被处理?/是否异步流保持对象存活

精确度在这里很重要。对象不会被自动处理。它总是在代码中显式地完成,通过使用语句或调用Dispose()方法。所以,如果你不在代码中进行dispose处理,也不会出现问题。

你可能想说的是"垃圾收集"。这在。net中是非常直接的,只要垃圾收集器可以看到对对象的引用,并且该引用由另一个本身是活的对象持有,那么该对象将不会被收集。

然而,

引用的存储位置并不总是那么清楚。c#编译器可以重写代码,并将其从类中的方法移动到隐藏类的方法中。这个隐藏的类有一个不可言说的名称,并有一个存储引用的字段。垃圾收集器可以看到,从而防止对象被收集。将代码中的引用复制到隐藏类对象的字段中的技术术语是"变量捕获"。

这个代码重写技巧在c#的很多地方都有使用。最初在语言中实现,以支持匿名方法和迭代器。并在后来的版本中进行了扩展,以实现lambda表达式和异步方法。查看正在发生的事情的一个好方法是查看c#编译器生成的代码。通过ildasm.exe或不完善的反编译器可见。否则,这当然符合"足够聪明"的称号。

在您的情况下,您的命令不会被处理,因为它有一个委托/回调引用。这意味着,只要委托存在,您的命令对象就会被委托保持活动状态。最终,在回调执行之后,GC将选择未触碰的(没有根的对象)并相应地处置。

更新:

另一种情况是,如果没有回调引用怎么办?

在这种情况下,您的对象不符合立即进行垃圾收集的条件,因为EPM(您在代码中遵循的模式)API在线程池中保留对请求的引用,特别是IO完成线程。此提示GC在完成之前不要触碰或收集。