簡體   English   中英

為什么空合並運算符(??)在這種情況下不起作用?

[英]Why doesn't the null coalescing operator (??) work in this situation?

當我運行此代碼時,我得到一個意外的NullReferenceException ,省略了fileSystemHelper參數(因此將其默認為null):

public class GitLog
    {
    FileSystemHelper fileSystem;

    /// <summary>
    ///   Initializes a new instance of the <see cref="GitLog" /> class.
    /// </summary>
    /// <param name="pathToWorkingCopy">The path to a Git working copy.</param>
    /// <param name="fileSystemHelper">A helper class that provides file system services (optional).</param>
    /// <exception cref="ArgumentException">Thrown if the path is invalid.</exception>
    /// <exception cref="InvalidOperationException">Thrown if there is no Git repository at the specified path.</exception>
    public GitLog(string pathToWorkingCopy, FileSystemHelper fileSystemHelper = null)
        {
        this.fileSystem = fileSystemHelper ?? new FileSystemHelper();
        string fullPath = fileSystem.GetFullPath(pathToWorkingCopy); // ArgumentException if path invalid.
        if (!fileSystem.DirectoryExists(fullPath))
            throw new ArgumentException("The specified working copy directory does not exist.");
        GitWorkingCopyPath = pathToWorkingCopy;
        string git = fileSystem.PathCombine(fullPath, ".git");
        if (!fileSystem.DirectoryExists(git))
            {
            throw new InvalidOperationException(
                "There does not appear to be a Git repository at the specified location.");
            }
        }

當我單步執行調試器中的代碼時,在我跳過第一行(使用??運算符)后, fileSystem仍然具有null值,如此屏幕fileSystem所示(踩到下一行拋出NullReferenceException ): 什么時候為null不為空?

這不是我的預期! 我期望null合並運算符發現參數為null並創建一個new FileSystemHelper() 我已經盯着這段代碼多年了,看不出它有什么問題。

ReSharper指出該字段僅用於這一方法,因此可能會被轉換為局部變量......所以我試過這個並猜猜是什么? 有效。 所以,我有我的修復,但我不能為我的生活看到為什么上面的代碼不起作用。 我覺得我正處於學習C#有趣的東西的邊緣,無論是那個還是我做過一些非常愚蠢的事情。 誰能看到這里發生了什么?

我在VS2012中使用以下代碼復制了它:

public void Test()
{
    TestFoo();
}

private Foo _foo;

private void TestFoo(Foo foo = null)
{
    _foo = foo ?? new Foo();
}

public class Foo
{
}

如果在TestFoo方法的末尾設置斷點,您可能會看到_foo變量集,但它仍將在調試器中顯示為null。

但是,如果你隨后對_foo任何事情 ,那么它就會正確顯示。 即使是簡單的任務,如

_foo = foo ?? new Foo();
var f = _foo;

如果你單步執行它,你會看到_foo顯示為null,直到它被賦值給f

這讓我想起了延遲執行行為,例如LINQ,但我找不到任何可以證實的行為。

完全有可能這只是調試器的一個怪癖。 也許擁有MSIL技能的人可以了解幕后發生的事情。

同樣有趣的是,如果用等效的替換null合並運算符:

_foo = foo != null ? foo : new Foo();

然后它不會表現出這種行為。

我不是匯編/ MSIL人,但只是看看兩個版本之間的dissasembly輸出很有意思:

        _foo = foo ?? new Foo();
0000002d  mov         rax,qword ptr [rsp+68h] 
00000032  mov         qword ptr [rsp+28h],rax 
00000037  mov         rax,qword ptr [rsp+60h] 
0000003c  mov         qword ptr [rsp+30h],rax 
00000041  cmp         qword ptr [rsp+68h],0 
00000047  jne         0000000000000078 
00000049  lea         rcx,[FFFE23B8h] 
00000050  call        000000005F2E8220 
        var f = _foo;
00000055  mov         qword ptr [rsp+38h],rax 
0000005a  mov         rax,qword ptr [rsp+38h] 
0000005f  mov         qword ptr [rsp+40h],rax 
00000064  mov         rcx,qword ptr [rsp+40h] 
00000069  call        FFFFFFFFFFFCA000 
0000006e  mov         r11,qword ptr [rsp+40h] 
00000073  mov         qword ptr [rsp+28h],r11 
00000078  mov         rcx,qword ptr [rsp+30h] 
0000007d  add         rcx,8 
00000081  mov         rdx,qword ptr [rsp+28h] 
00000086  call        000000005F2E72A0 
0000008b  mov         rax,qword ptr [rsp+60h] 
00000090  mov         rax,qword ptr [rax+8] 
00000094  mov         qword ptr [rsp+20h],rax 

將其與內聯if版本進行比較:

        _foo = foo != null ? foo : new Foo();
0000002d  mov         rax,qword ptr [rsp+50h] 
00000032  mov         qword ptr [rsp+28h],rax 
00000037  cmp         qword ptr [rsp+58h],0 
0000003d  jne         0000000000000066 
0000003f  lea         rcx,[FFFE23B8h] 
00000046  call        000000005F2E8220 
0000004b  mov         qword ptr [rsp+30h],rax 
00000050  mov         rax,qword ptr [rsp+30h] 
00000055  mov         qword ptr [rsp+38h],rax 
0000005a  mov         rcx,qword ptr [rsp+38h] 
0000005f  call        FFFFFFFFFFFCA000 
00000064  jmp         0000000000000070 
00000066  mov         rax,qword ptr [rsp+58h] 
0000006b  mov         qword ptr [rsp+38h],rax 
00000070  nop 
00000071  mov         rcx,qword ptr [rsp+28h] 
00000076  add         rcx,8 
0000007a  mov         rdx,qword ptr [rsp+38h] 
0000007f  call        000000005F2E72A0 
        var f = _foo;
00000084  mov         rax,qword ptr [rsp+50h] 
00000089  mov         rax,qword ptr [rax+8] 
0000008d  mov         qword ptr [rsp+20h],rax 

基於此,我確實認為存在某種延遲執行。 與第一個示例相比,第二個示例中的賦值語句非常小。

其他人在這個問題上遇到了同樣的問題。 有趣的是,它也使用了this._field = expression ?? new ClassName(); this._field = expression ?? new ClassName(); 格式。 它可能是調試器的某種問題,因為寫出值似乎可以為它們產生正確的結果。

嘗試添加調試/日志代碼以在分配后顯示字段的值,以消除附加調試器中的怪異。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM