C# Hangfire BackgroundJob.排队和方法序列化
使用hangfire,我们可以执行以下操作:C# Hangfire BackgroundJob.排队和方法序列化,c#,hangfire,C#,Hangfire,使用hangfire,我们可以执行以下操作: public MyClass { public void RunJob() { SomeClass x = new SomeClass(); x.SomeProperty = "Test"; Hangfire.BackgroundJob.Enqueue(() => x.SomeMethod()); } } 假设SomeMethod不是静态的,并且取决于SomeClass.
public MyClass
{
public void RunJob()
{
SomeClass x = new SomeClass();
x.SomeProperty = "Test";
Hangfire.BackgroundJob.Enqueue(() => x.SomeMethod());
}
}
假设SomeMethod
不是静态的,并且取决于SomeClass.SomeProperty的值。如果SomeMethod
不是静态的,那么它如何工作?对象x
将在两行后超出范围。Hangfire是否会增加对对象x
的引用计数,并且垃圾收集器在Hangfire处理完对象之前不会清理该对象
此外,假设SomeClass
实现IDisposable,而SomeMethod
依赖于Dispose清理的资源:
public MyClass
{
public void RunJob()
{
using (SomeClass x = new SomeClass())
{
x.SomeProperty = "Test";
Hangfire.BackgroundJob.Enqueue(() => x.SomeMethod());
}
}
}
在这种情况下,可能会在运行作业之前调用x.Dispose。这会导致错误吗
在测试中,我可以看到私有成员SomeClass.\u disposed在using语句后被设置为true,但是当Hangfire在几秒钟后调用SomeMethod时,SomeClass.\u disposed被设置为false!这黑魔法是怎么发生的
观察结果
我修改了类以包括:
public MyClass
{
public static int LastId = 0;
private static int Id = 0;
public MyClass()
{
Id = ++LastId;
}
public void RunJob()
{
using (SomeClass x = new SomeClass())
{
x.SomeProperty = "Test";
Hangfire.BackgroundJob.Enqueue(() => x.SomeMethod());
}
}
}
。。。使用这个,我可以观察到Hangfire使用的类的Id
,与我在第一个示例中使用的实例不同。因此,我假设Enqueue创建了对象x的一个副本,或者可能是()=>操作符
在测试中,我可以看到私有成员SomeClass.\u disposed设置为
using语句后为true,但当Hangfire调用SomeMethod时
秒后,SomeClass.\u disposed设置为false!这是怎么回事
黑魔法发生了
因为两个x
都不是相同的对象。hangfire运行的程序是主程序运行的程序反序列化的结果,主程序在Enquence时已序列化
在这种情况下,可能会在运行作业之前调用x.Dispose。
这会导致错误吗
这可能会导致错误。例如,如果在与主程序相同的appdomain中运行hangfire,并且如果处置x
,则也处置将由hangfire反序列化的x
使用的共享资源。对我来说,处理作为enqueing操作一部分的对象似乎是一种代码味道,因为这些对象是可序列化的
看看排队
方法。您会注意到它将表达式
作为参数(而不仅仅是操作
)。
这个表达式将被序列化,以及它的所有参数和常量,并在Hangfire退出队列时被反序列化。由于它正在工作,我只能看到一个可能的解释:Hangfire序列化参数(在本例中包括x
),并将其存储在数据库中。当该运行任务时,它会再次序列化,并创建一个新实例。文档中的一页说,这就是参数的处理方式-所以我想x
可以作为参数(至少对Hangfire来说)我还没有读过源代码-但是私人成员可以使用反射。所以这至少是他们使用的一种可能的解决方案。你必须通读这本书才能确定答案。@fredrik谢谢你。