2

考虑以下代码:

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”方法后对象 basecommand 被释放?

连 .net 都知道 EndCommand 有回调方法吗?

或者.net 是否足够智能以保持对象处于活动状态,直到异步流程完成?

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

4

2 回答 2

3

准确性在这里很重要。对象不会自动处置。它总是在您的代码中显式完成,无论是通过using语句还是调用 Dispose() 方法。因此,如果您不在代码中进行处置,则永远不会有问题。

您可能想说的是“垃圾收集”。这在 .NET 中非常简单,只要垃圾收集器可以看到对对象的引用,并且该引用由另一个本身还活着的对象持有,那么就不会收集对象。

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

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

于 2013-05-30T10:49:07.717 回答
1

在您的情况下,您的命令将不会被释放,因为它具有委托/回调引用。这意味着,只要委托存在,您的命令对象将由委托保持活动状态。最终,一旦回调被执行,GC 将选择未触及的(没有根的对象)进行相应的处理。

更新:

其他情况是,如果没有回调引用怎么办。

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

于 2013-05-30T09:00:45.923 回答