简体   繁体   English

为什么是 SynchronizationContext.Current null?

[英]Why is SynchronizationContext.Current null?

Error: Object reference not set to an instance of an object.错误: Object reference not set to an instance of an object.

The algorithm below works.下面的算法有效。 I tried it, then I removed the Winform project to another directory and SynchronizationContext.Current is null .我试过了,然后我将null项目删除到另一个目录, SynchronizationContext.CurrentWinform Why?为什么?

SynchronizationContext uiCtx = SynchronizationContext.Current;  

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    int[] makeSelfMoves = new int[4];

    lock (replay)
    {
        // count should be more than 2
        foreach (KeyValuePair<int, int[]> item in replay)
        {              
            makeSelfMoves = replay[item.Key];
            codeFile.ExecuteAll(makeSelfMoves[0],
              makeSelfMoves[1], makeSelfMoves[2], makeSelfMoves[3]);

            // i get the error here. uictx is null
            uiCtx.Post(o =>
            {
                PrintPieces(codeFile.PieceState());
            }, null);                               

            System.Threading.Thread.Sleep(1000);
        }
    }
}

Your code critically depends on exactly when and where the constructor of your class runs.您的代码主要取决于 class 的构造函数运行的确切时间和位置。 SynchronizationContext.Current will be null when: SynchronizationContext.Current 在以下情况下将为 null:

  • your class object is created too soon, before your code creates an instance of the Form class or calls Application.Run() in Main().您的 class object 创建得太早,在您的代码创建表单 class 的实例或调用 Main() 中的 Application.Run() 之前。 That's when the Current member is set to an instance of WindowsFormsSynchronizationContext, the class that knows how to marshal calls with the message loop.那时 Current 成员被设置为 WindowsFormsSynchronizationContext 的一个实例,class 知道如何使用消息循环编组调用。 Fix this by moving your object instancing code to the main form constructor.通过将 object 实例化代码移动到主窗体构造函数来解决此问题。

  • your class object is created on any thread other than the main UI thread.您的 class object 是在主 UI 线程以外的任何线程上创建的。 Only the UI thread in a Winforms application can marshal calls.只有 Winforms 应用程序中的 UI 线程可以编组调用。 Diagnose this by adding a constructor to your class with this statement:通过使用以下语句向 class 添加构造函数来诊断此问题:

     Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId);

Also add this line to the Main() method in Program.cs.还要将此行添加到 Program.cs 中的 Main() 方法。 It won't work if the displayed value in the Output window is different.如果 Output window 中的显示值不同,它将不起作用。 Fix this by moving your object instancing code to, again, the main form constructor so you can be sure it runs on the UI thread.通过将 object 实例化代码再次移动到主窗体构造函数来解决此问题,这样您就可以确保它在 UI 线程上运行。

I ran into this issue when creating WinForms via dependency injection in my test framework.在我的测试框架中通过依赖注入创建 WinForms 时遇到了这个问题。 Originally I would capture the SynchronizationContext.Current in my constructor:最初我会在我的构造函数中捕获 SynchronizationContext.Current:

private readonly SynchronizationContext UISyncCtxt;

public MyWinFormViewModel ()
{
    UISyncCtxt = SynchronizationContext.Current;
    ...
}

This worked fine if this MyWinFormViewModel was created while an application was already running, but this isn't necessarily the situation when creating the dependency graph in the test harness.如果这个 MyWinFormViewModel 是在应用程序已经运行时创建的,这很好用,但在测试工具中创建依赖关系图时不一定是这种情况。 When created by the test harness, SynchronizationContext.Current would be null, and there'd be a null reference exception later.当由测试工具创建时,SynchronizationContext.Current 将为 null,稍后会出现 null 引用异常。

My solution was to "lazily" evaluate it as follows:我的解决方案是“懒惰地”评估它,如下所示:

    private SynchronizationContext _uisyncctxt;

    private SynchronizationContext UISyncCtxt => 
        _uisyncctxt ??= SynchronizationContext.Current;

By the time I actually need the context (to update controls on the form), it's assured to be present (because the form has been instantiated).当我真正需要上下文(更新表单上的控件)时,它肯定存在(因为表单已经被实例化)。

EDIT: Peter Duniho brought up a valid point about arbitrarily grabbing the synchronization context.编辑:Peter Duniho 提出了一个关于任意获取同步上下文的有效观点。 My original answer also makes this class dishonest about its dependencies since it relies on this context, but doesn't request it through the constructor or other injectable method.我的原始答案也使这个 class 对其依赖关系不诚实,因为它依赖于这个上下文,但没有通过构造函数或其他可注入方法请求它。 Since this class uses DI, I added a dependency called IUISyncContext, which has the following signature:由于这个 class 使用 DI,我添加了一个名为 IUISyncContext 的依赖项,它具有以下签名:

public interface IUISyncContext
{
    SynchronizationContext UISyncContext { get; }
}

...and the constructor for my view model: ...以及我认为 model 的构造函数:

private readonly SynchronizationContext UISyncCtxt;

public MyWinFormViewModel (IUISyncContext syncContext)
{        
    UISyncCtxt = syncContext.UISyncContext;
    ...
}

Thanks for the feedback, Peter.感谢您的反馈,彼得。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么我的Winforms应用程序中的SynchronizationContext.Current为null? - Why is SynchronizationContext.Current null in my Winforms application? 在WPF中使用Unity解析时,SynchronizationContext.Current为null - SynchronizationContext.Current is null on resolving with Unity in WPF 主线程上的SynchronizationContext.Current为null - SynchronizationContext.Current is null on Main thread SynchronizationContext.Current 在主 UI 线程上的 Continuation 中为 null - SynchronizationContext.Current is null in Continuation on the main UI thread 解决.NET 4.0中SynchronizationContext.Current为空的问题 - Workaround for issue in .NET 4.0 where SynchronizationContext.Current is null 当SynchronizationContext.Current为null时,我可以安全地使用Task.Wait吗? - Can I safely use Task.Wait when SynchronizationContext.Current is null? 主线程的SynchronizationContext.Current如何在Windows窗体应用程序中变为空? - How can SynchronizationContext.Current of the main thread become null in a Windows Forms application? 当线程返回到线程池时,SynchronizationContext.Current是否重置 - Is SynchronizationContext.Current reset when a thread goes back to threadpool 线程中的C#线程:如何获取SynchronizationContext.Current? - C# Thread in Thread: how to get SynchronizationContext.Current? 当前的SynchronizationContext可以为null吗? - Can the current SynchronizationContext be null?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM