请考虑以下代码:
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是否足够智能以保持对象存活直到异步流完成?
如果对象不活动,我该怎么做才能指示垃圾收集器不要处理basecommand?
答案 0 :(得分:3)
准确性在这里很重要。对象不会自动处理。它总是在代码中显式完成,可以通过 using 语句或调用Dispose()方法完成。因此,如果您不在代码中处置,那么从来没有问题。
你可能想说的是&#34;垃圾收集&#34;。这在.NET中是非常简单的,只要垃圾收集器可以看到对象的引用,并且该引用由另一个本身存活的对象持有,那么就不会收集对象。
然而,并不总是很清楚存储该引用的位置。 C#编译器可以重写您的代码并将其从类中的方法移动到隐藏类的方法。隐藏的类具有不可言喻的名称,并且具有存储引用的字段。垃圾收集器可以看到哪个,从而防止收集对象。将代码中的引用复制到该隐藏类对象的字段中的技术术语是"variable capturing"。
此代码重写技巧在C#中的许多地方使用。最初用语言实现,以支持匿名方法和迭代器。并在以后的版本中进行扩展,以实现lambda表达式和异步方法。查看正在发生的事情的好方法是查看C#编译器生成的代码。使用ildasm.exe或不完美的反编译器可见。否则这肯定适合足够聪明的&#34;绰号。
答案 1 :(得分:1)
在您的情况下,您的命令将不会被处置,因为它具有委托/回调引用。这意味着,只要代理人活着,命令对象将由代理保持活动状态。最后,一旦执行了回调,GC就会选择不接触(没有root的对象)。
更新:
其他情况是,如果没有回调参考,该怎么办。
在这种情况下,您的对象不会立即进行垃圾回收,因为EPM(您在代码中遵循的模式)API会在线程池中保留对您的请求的引用,特别是IO完成线程。这提示GC在完成之前不要触摸或收集。