C# ThreadPool QueueUserWorkItem引发NullReferenceException

C# ThreadPool QueueUserWorkItem引发NullReferenceException,c#,.net,wpf,threadpool,windows-error-reporting,C#,.net,Wpf,Threadpool,Windows Error Reporting,这是一个有点奇怪的问题,因为我无法复制它。我有两个能够复制此问题的客户,他们向我发送了WER日志 我有一个C#应用程序,它将工作项排队并在后台执行。在一小部分机器中,在尝试执行工作线程的第一行时,它会立即抛出一个NPE Ausnahmeinformationen: System.NullReferenceException bei magicsim.SimcPreloaderData+<>c__DisplayClass16_0.<LoadArmoryData>b__

这是一个有点奇怪的问题,因为我无法复制它。我有两个能够复制此问题的客户,他们向我发送了WER日志

我有一个C#应用程序,它将工作项排队并在后台执行。在一小部分机器中,在尝试执行工作线程的第一行时,它会立即抛出一个NPE

Ausnahmeinformationen: System.NullReferenceException
   bei magicsim.SimcPreloaderData+<>c__DisplayClass16_0.<LoadArmoryData>b__0(System.Object)
   bei System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(System.Object)
   bei System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   bei System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   bei System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   bei System.Threading.ThreadPoolWorkQueue.Dispatch()
   bei System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
所以这是在方法29b中,试图点击IL行
fb

使用ILDASM,我可以验证此问题签名的位置是否与堆栈跟踪匹配(SimcPreloaderData)

编辑2(完整性):

事实上,29b指的是b__0,而不是LoadArmoryData

如果查看ILSpy中的正确方法,您会看到以下命令序列,这意味着明确的问题和潜在的解决方案

// string contents = simcString + "\nsave=./characters/" + value + ".simc";
IL_00ce: ldarg.0
IL_00cf: ldfld string magicsim.SimcPreloaderData/'<>c__DisplayClass16_0'::simcString
IL_00d4: ldstr "\nsave=./characters/"
IL_00d9: ldloc.0
IL_00da: ldstr ".simc"
IL_00df: call string [mscorlib]System.String::Concat(string, string, string, string)
IL_00e4: stloc.1
// File.WriteAllText("characters/" + value + ".simc", contents);
IL_00e5: ldstr "characters/"
IL_00ea: ldloc.0
IL_00eb: ldstr ".simc"
IL_00f0: call string [mscorlib]System.String::Concat(string, string, string)
IL_00f5: ldloc.1
IL_00f6: call void [mscorlib]System.IO.File::WriteAllText(string, string)
// if (simc.RunSim("characters/" + value + ".simc"))
IL_00fb: ldarg.0
IL_00fc: ldfld class magicsim.SimC magicsim.SimcPreloaderData/'<>c__DisplayClass16_0'::simc
IL_0101: ldstr "characters/"
IL_0106: ldloc.0
IL_0107: ldstr ".simc"
IL_010c: call string [mscorlib]System.String::Concat(string, string, string)
IL_0111: callvirt instance bool magicsim.SimC::RunSim(string)
// (no C# code)
IL_0116: brfalse.s IL_0163
//string contents=simcString+“\nsave=./characters/“+value+”.simc”;
IL\u 00ce:ldarg.0
IL_00cf:ldfld string magicsim.SimcPreloaderData/'c_udisplayClass16_0':simcString
IL\U 00d4:ldstr“\n保存=./characters/”
IL_00d9:ldloc.0
IL_00da:ldstr“.simc”
IL_00df:call string[mscorlib]System.string::Concat(string,string,string,string)
IL_00e4:stloc.1
//File.writealText(“characters/”+value+“.simc”,contents);
IL_00e5:ldstr“字符/
IL_00ea:ldloc.0
IL_00eb:ldstr“.simc”
IL_00f0:调用字符串[mscorlib]系统。字符串::Concat(字符串,字符串,字符串)
IL_00f5:ldloc.1
IL_00f6:调用void[mscorlib]System.IO.File::WriteAllText(字符串,字符串)
//if(simc.RunSim(“字符/”+值+“.simc”))
IL_00fb:ldarg.0
IL_00fc:ldfld类magicsim.SimC magicsim.SimcPreloaderData/'c_u显示类16_0'::SimC
IL_0101:ldstr“字符/
IL_0106:ldloc.0
IL_0107:ldstr“.simc”
IL_010c:call string[mscorlib]System.string::Concat(string,string,string)
IL_0111:callvirt实例bool magicsim.SimC::RunSim(字符串)
//(无C#代码)
IL_0116:brfalse.s IL_0163

我认为问题中的分析有缺陷(例如,异常来自
b_uu0(System.Object)
,它表示LoadArmoryData中的lambda表达式,其签名需要对象参数;但您正在查看LoadArmoryData的IL,它是一个签名需要字符串参数的方法)


这只是一个简单的NullReferenceException,可能来自
nameRegex.Match(simcString).Groups[2].Value当正则表达式不匹配时。

我认为问题中的分析有缺陷(例如,异常来自
b_u0(System.Object)
,它表示LoadArmoryData中的lambda表达式,其签名需要对象参数;但您正在查看LoadArmoryData的IL,它是一个签名需要字符串参数的方法)


这只是一个简单的NullReferenceException,可能来自
nameRegex.Match(simcString).Groups[2].Value当正则表达式不匹配时。

@MickyD添加以供参考。这是一个猜测,但。。。我想知道表示lambda的对象是否因为内存压力过高而被垃圾收集。我不确定像这样的代表的生命周期特征。也许这条评论会触发某人说“嘿,等一下,是的”(或者更可能是“不,Flydog,那不可能”)。不确定这是否相关,但没有必要在lambda之外声明
simc
。@MickyD补充以供参考。这是一个疯狂的猜测,但是。。。我想知道表示lambda的对象是否因为内存压力过高而被垃圾收集。我不确定像这样的代表的生命周期特征。也许这条评论会触发某人说“嘿,等一下,是的”(或者更可能是“不,Flydog,那不可能”)。不确定这是否相关,但没有必要在lambda之外声明
simc
。你是对的,我在发布这条消息后意识到了这一点,并试图与客户确认。如果查看ILSpy中的
b_uu0
,您会发现IL_00fb是
If(simc.RunSim(“characters/”+value+“.simc”)
的开始,鉴于问题的领域,在这种情况下,simc可能为空。我必须与客户确认此依赖关系未正确解决的原因(并在值也为null的情况下进行验证)。您是正确的,我在发布此内容后意识到这一点,并试图与客户确认。如果查看ILSpy中的
b_uu0
,您会发现IL_00fb是
If(simc.RunSim(“characters/”+value+“.simc”)
的开始,鉴于问题的领域,在这种情况下,simc可能为空。我必须向客户确认为什么这个依赖关系没有得到正确的解决(并且在值也为null的情况下进行验证)。
Method #2 (0600029b) 
    -------------------------------------------------------
        MethodName: <LoadArmoryData>b__0 (0600029B)
        Flags     : [Assem] [HideBySig] [ReuseSlot]  (00000083)
        RVA       : 0x0000d338
        ImplFlags : [IL] [Managed]  (00000000)
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        1 Arguments
            Argument #1:  Object
        1 Parameters
            (1) ParamToken : (0800020f) Name : _ flags: [none] (00000000)
.method public hidebysig 
    instance void LoadArmoryData (
        string simcString
    ) cil managed 
{
    // Method begins at RVA 0x7b4d
    // Code size 48 (0x30)
    .maxstack 8

    IL_0000: newobj instance void magicsim.SimcPreloaderData/'<>c__DisplayClass16_0'::.ctor()
    IL_0005: dup
    IL_0006: ldarg.0
    IL_0007: stfld class magicsim.SimcPreloaderData magicsim.SimcPreloaderData/'<>c__DisplayClass16_0'::'<>4__this'
    IL_000c: dup
    IL_000d: ldarg.1
    IL_000e: stfld string magicsim.SimcPreloaderData/'<>c__DisplayClass16_0'::simcString
    IL_0013: ldarg.0
    IL_0014: ldstr "Acquiring SimC Executable"
    IL_0019: call instance void magicsim.SimcPreloaderData::set_Label(string)
    IL_001e: ldftn instance void magicsim.SimcPreloaderData/'<>c__DisplayClass16_0'::'<LoadArmoryData>b__0'(object)
    IL_0024: newobj instance void [mscorlib]System.Threading.WaitCallback::.ctor(object, native int)
    IL_0029: call bool [mscorlib]System.Threading.ThreadPool::QueueUserWorkItem(class [mscorlib]System.Threading.WaitCallback)
    IL_002e: pop
    IL_002f: ret
} // end of method SimcPreloaderData::LoadArmoryData
public void LoadArmoryData(String simcString)
{
    SimC simc;
    Label = "Acquiring SimC Executable";
    ThreadPool.QueueUserWorkItem((_) =>
    {
        try
        {
            simc = SimCManager.AcquireSimC();
        }
        catch (Exception e)
        {
            MessageBox.Show("Could not acquire SimC because of an Exception: " + e.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            App.Current.Dispatcher.Invoke(() =>
            {
                PreloadingFailed(this, new EventArgs());
            });
            return;
        }
        Label = "Generating SimC Profile";
        Regex nameRegex = new Regex("(warrior|paladin|hunter|rogue|priest|deathknight|shaman|mage|warlock|monk|druid|demonhunter)+=\"?([^\r\n\"]+)\"?");
        String name = nameRegex.Match(simcString).Groups[2].Value;
        String text = simcString + "\nsave=./characters/" + name + ".simc";
        try
        {
            if (!Directory.Exists("characters"))
            {
                Directory.CreateDirectory("characters");
            }
            if (File.Exists("characters/" + name))
            {
                File.Delete("characters/" + name);
            }
            File.WriteAllText("characters/" + name + ".simc", text);
        }
        catch (UnauthorizedAccessException e)
        {
            MessageBox.Show("Could not write character profile due to a permissions issue. Please retry, running as Administrator." + e.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            App.Current.Dispatcher.Invoke(() =>
            {
                PreloadingFailed(this, new EventArgs());
            });
            return;
        }
        if (simc.RunSim("characters/" + name + ".simc"))
        {
            Label = "SimC Profile Generated";
            charName = name;
            App.Current.Dispatcher.Invoke(() =>
            {
                PreloadingComplete(this, new EventArgs());
            });
        }
        else
        {
            Label = "Failed to Generate Profile";
            MessageBox.Show("Failed to generate profile. Please check your input and try again.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);

            App.Current.Dispatcher.Invoke(() =>
            {
                PreloadingFailed(this, new EventArgs());
            });
        }
    });
}
// string contents = simcString + "\nsave=./characters/" + value + ".simc";
IL_00ce: ldarg.0
IL_00cf: ldfld string magicsim.SimcPreloaderData/'<>c__DisplayClass16_0'::simcString
IL_00d4: ldstr "\nsave=./characters/"
IL_00d9: ldloc.0
IL_00da: ldstr ".simc"
IL_00df: call string [mscorlib]System.String::Concat(string, string, string, string)
IL_00e4: stloc.1
// File.WriteAllText("characters/" + value + ".simc", contents);
IL_00e5: ldstr "characters/"
IL_00ea: ldloc.0
IL_00eb: ldstr ".simc"
IL_00f0: call string [mscorlib]System.String::Concat(string, string, string)
IL_00f5: ldloc.1
IL_00f6: call void [mscorlib]System.IO.File::WriteAllText(string, string)
// if (simc.RunSim("characters/" + value + ".simc"))
IL_00fb: ldarg.0
IL_00fc: ldfld class magicsim.SimC magicsim.SimcPreloaderData/'<>c__DisplayClass16_0'::simc
IL_0101: ldstr "characters/"
IL_0106: ldloc.0
IL_0107: ldstr ".simc"
IL_010c: call string [mscorlib]System.String::Concat(string, string, string)
IL_0111: callvirt instance bool magicsim.SimC::RunSim(string)
// (no C# code)
IL_0116: brfalse.s IL_0163