後來我編譯了兩個版本的代碼,一個使用(Nullable<T>)x.GetValueOrDefault(y)
,另一個使用(Nullable<T>)x ?? y)
。空合併操作符含義?
在反編譯爲IL後,我注意到空合併運算符被轉換爲GetValueOrDefault
調用。
由於這是一個方法調用,可以傳遞一個表達式,該表達式在執行該方法之前被評估,因此似乎總是執行y
。
例如:
using System;
public static class TestClass
{
private class SomeDisposable : IDisposable
{
public SomeDisposable()
{
// Allocate some native resources
}
private void finalize()
{
// Free those resources
}
~SomeDisposable()
{
finalize();
}
public void Dispose()
{
finalize();
GC.SuppressFinalize(this);
}
}
private struct TestStruct
{
public readonly SomeDisposable _someDisposable;
private readonly int _weirdNumber;
public TestStruct(int weirdNumber)
{
_weirdNumber = weirdNumber;
_someDisposable = new SomeDisposable();
}
}
public static void Main()
{
TestStruct? local = new TestStruct(0);
TestStruct local2 = local ?? new TestStruct(1);
local2._someDisposable.Dispose();
}
}
似乎導致成不適對象,並可能影響性能了。
首先,這是真的嗎?或者JIT或類似的東西改變了實際執行的ASM代碼?
其次,有人可以解釋爲什麼它有這種行爲?
NOTE:這只是一個例子,它不是基於真實的代碼,並且請不要發表評論,如「這是錯誤的代碼」。
IL DASM:
好的,當我.Net框架2.0編譯此它導致相同碼與呼叫空聚結和GetValueOrDefault。使用.NET Framework 4.0中,它會產生這兩個代碼:
GetValueOrDefault:
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 19 (0x13)
.maxstack 2
.locals init ([0] valuetype [mscorlib]System.Nullable`1<int32> nullableInt,
[1] int32 nonNullableInt)
IL_0000: nop
IL_0001: ldloca.s nullableInt
IL_0003: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_0009: ldloca.s nullableInt
IL_000b: ldc.i4.1
IL_000c: call instance !0 valuetype [mscorlib]System.Nullable`1<int32>::GetValueOrDefault(!0)
IL_0011: stloc.1
IL_0012: ret
} // end of method Program::Main
空凝聚:
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 32 (0x20)
.maxstack 2
.locals init (valuetype [mscorlib]System.Nullable`1<int32> V_0,
int32 V_1,
valuetype [mscorlib]System.Nullable`1<int32> V_2)
IL_0000: nop
IL_0001: ldloca.s V_0
IL_0003: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_0009: ldloc.0
IL_000a: stloc.2
IL_000b: ldloca.s V_2
IL_000d: call instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue()
IL_0012: brtrue.s IL_0017
IL_0014: ldc.i4.1
IL_0015: br.s IL_001e
IL_0017: ldloca.s V_2
IL_0019: call instance !0 valuetype [mscorlib]System.Nullable`1<int32>::GetValueOrDefault()
IL_001e: stloc.1
IL_001f: ret
} // end of method Program::Main
事實證明,這是不再的情況下並且當HasValue
返回false時,它完全跳過GetValueOrDefault
呼叫。
如果'y'是一個方法的調用,導致需要處理的對象,那麼在任何情況下都有泄漏,即'x'爲空。 – 2012-01-08 19:46:47
@ M.Babcock不是真的泄漏,只是推遲清理內存。看看修改後的例子,我希望這能更好地解釋這個問題。 – Aidiakapi 2012-01-08 20:07:00
其實我說錯了,如果'local'不是null並且實際調用了方法,那麼你將會泄漏,因爲結果將從GC中收集而不被處置。要回答每次是否實際調用方法的問題,可以在方法中放置一個斷點並運行它。 – 2012-01-08 20:17:27