我一直在找你,有些代码无效。除了下面一行,一切看起来都很好。
Transport = Transport?? MockITransportUtil.GetMock(true);
在执行该行之前,Transport为null。我看到GetMock已执行,并且它返回一个非null对象。在该行之后,运输仍为空;
我看着生成的IL,它对我来说很好看。
IL_0002: ldarg.0
IL_0003: ldfld class [Moq]Moq.Mock`1<class [CommLibNet]CommLibNET.ITransport> Curex.Services.Common.UnitTests.Messaging.TestIGuaranteedSubscriptionBase::Transport
IL_0008: dup
IL_0009: brtrue.s IL_0012
IL_000b: pop
IL_000c: ldc.i4.1
IL_000d: call class [Moq]Moq.Mock`1<class [CommLibNet]CommLibNET.ITransport> Curex.Services.Common.UnitTests.Mocking.MockITransportUtil::GetMock(bool)
IL_0012: stfld class [Moq]Moq.Mock`1<class [CommLibNet]CommLibNET.ITransport> Curex.Services.Common.UnitTests.Messaging.TestIGuaranteedSubscriptionBase::Transport
我们看到函数被调用,stfld应该获取返回值并设置字段。
所以我然后查看了我看到调用的程序集,但看起来RAX中的返回被下一次调用吹走了并且丢失了。
Transport = Transport?? MockITransportUtil.GetMock(true);
000007FE9236F776 mov rax,qword ptr [rbp+0B0h]
000007FE9236F77D mov rax,qword ptr [rax+20h]
000007FE9236F781 mov qword ptr [rbp+20h],rax
000007FE9236F785 mov rcx,qword ptr [rbp+20h]
000007FE9236F789 mov rax,qword ptr [rbp+0B0h]
000007FE9236F790 mov qword ptr [rbp+28h],rax
000007FE9236F794 test rcx,rcx
000007FE9236F797 jne 000007FE9236F7AC
000007FE9236F799 mov cl,1
000007FE9236F79B call 000007FE92290608
//var x = ReferenceEquals(null, Transport) ? MockITransportUtil.GetMock(true) : Transport;
ListerFactory = ListerFactory ?? MockIListenerUtil.GetMockSetupWithAction((a) => invokingAction = a);
000007FE9236F7A0 mov qword ptr [rbp+30h],rax
000007FE9236F7A4 mov rax,qword ptr [rbp+30h]
000007FE9236F7A8 mov qword ptr [rbp+20h],rax
000007FE9236F7AC mov rcx,qword ptr [rbp+28h]
如果我使用if语句或?:运算符,则每个工作正常。
Visual Studio 2013
我创造了一个psudo最小的复制品。
class simple
{
public A MyA = null;
public B MyB = null;
public void SetUp()
{
MyA = MyA ?? new A();
MyB = new B();// Put breakpoint here
}
}
如果在指定的行上设置断点并在调试器中查看MyA的值,它仍将为null(仅当在x64中构建时)。如果你执行下一行,它将设置值。我没有能够重现没有发生的评估。它在反汇编中非常清楚,在分配之前,下一行的执行已经开始。
以下是ms连接网站的link
答案 0 :(得分:10)
MyB = new B();// Put breakpoint here
问题是断点,而不是代码生成。 x64抖动会导致这种情况发生,它会产生不准确的调试信息。它使用仍然是前一个语句一部分的代码地址错误地发出语句的行号信息。
你可以从你发布的反汇编中看出,地址F7A0到F7A8的代码仍然是??声明。 F7AC的分支是真实的,这是下一个语句开始的地方。所以应该说F7AC是下一个语句的开头,而不是F7A0。
此错误的后果是调试器可能永远不会在断点处停止。您可以通过更改您的repro代码并编写public A MyA = new A();
来自己看到这一点。如果它 停止,则分配尚未执行。因此,在您的情况下,您仍然会看到具有先前值的变量 null 。一步就解决了它,尽管它取决于下一个语句的样子。
请放心,调试时只会出错,程序仍能正常运行。只要记住这个怪癖,afaik它只会出错?运营商。你可以告诉它不会得到太多使用:)虽然大多数程序员只调试他们程序的32位版本,默认的项目设置非常鼓励它。
正如我们所说,问题正在得到解决,不要指望您的Connect报告会产生影响,Microsoft非常清楚这个错误。微软的抖动团队有rewritten the x64 jitter completely,目前在CTP2。我估计它会被释放一年左右。
答案 1 :(得分:1)
我从MS得到了一个更新,这确实是一个真正的问题,并已在即将发布的x64 jiter中得到修复。