我一直在找你,有些代码无效.除了下面的一行,一切看起来都很好.
Transport = Transport?? MockITransportUtil.GetMock(true);
Run Code Online (Sandbox Code Playgroud)
执行该行之前,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
Run Code Online (Sandbox Code Playgroud)
我们看到函数被调用,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]
Run Code Online (Sandbox Code Playgroud)
如果我使用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
}
}
Run Code Online (Sandbox Code Playgroud)
如果在指定的行上设置断点并在调试器中查看MyA的值,它仍将为null(仅当在x64中构建时).如果你执行下一行,它将设置值.我没有能够重现没有发生的评估.它在反汇编中非常清楚,在分配发生之前,下一行的执行已经开始.
这是ms连接站点的链接
Han*_*ant 10
MyB = new B();// Put breakpoint here
Run Code Online (Sandbox Code Playgroud)
问题是断点,而不是代码生成.x64抖动会导致这种情况发生,它会产生不准确的调试信息.它使用仍然是前一个语句一部分的代码地址错误地发出语句的行号信息.
从你发布的反汇编中可以看出,地址F7A0到F7A8的代码仍然是?? 声明.F7AC的分支是真实的,这是下一个语句开始的地方.所以应该说F7AC是下一个声明的开始,而不是F7A0.
此错误的后果是调试器可能永远不会在断点处停止.您可以通过更改您的repro代码并写入来自己看到这一点.public A MyA = new A(); 如果它确实停止,那么分配还没有执行.所以你仍然看到变量具有前一个值,在你的情况下为null.一步就解决了它,尽管它取决于下一个语句的样子.
请放心,调试时这只会出错,程序仍能正常运行.只要记住这个怪癖,afaik它只会出错?运营商.你可以告诉它不会得到太多使用:)虽然大多数程序员只调试他们的程序的32位版本,默认项目设置大大鼓励它.
正如我们所说,问题正在得到解决,不要指望您的Connect报告产生影响,Microsoft非常清楚这个错误.微软的抖动团队完全重写了x64抖动,它目前在CTP2中.我估计它会被释放一年左右.