![](/img/trans.png)
[英]Why doesn't the null coalescing operator work on my nullable int when I convert it to a string?
[英]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並創建一個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.