C# Hangfire BackgroundJob.排队和方法序列化

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.

使用hangfire,我们可以执行以下操作:

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谢谢你。