聊聊 C# 7.2 不可變的結構設計
C# 7.2 來了一個新東西 readonly struct,就是可以宣告一個不可變的結構,大概長這樣子:
程式碼 1
public readonly struct MyStruct
{
private readonly int _y;
public int X { get; }
public MyStruct(int a)
{
X = a;
_y = a;
}
}
MyStrcuct 被宣告為 readonly struct,表示具有不可變動性 (immutable),因此它的欄位只能宣告為 readonly;屬性也只能有 getter 。也就是說,一旦建立起了 MyStruct 執行個體,它的內部欄位值是無法更改的。
這玩意大致上都是在防止防禦性複製的發生,在結構二三事(1)中提到其中一個狀況就是 readonly field,另外一個狀況則是方法參數宣告使用 in 參數修飾詞以及 readonly ref 的時候,例如:
程式碼 2
class Program
{
static void Main(string[] args)
{
}
void Test(in MyStruct s)
{
s.Request();
}
}
public struct MyStruct
{
private readonly int _y;
public int X { get; }
public MyStruct(int a)
{
X = a;
_y = a;
}
public void Request()
{ }
}
Test 方法在編譯後,會多產生一個臨時區域變數,觀察下方 IL code 的 locals init
.method private hidebysig instance void Test([in] valuetype ConsoleApp2.MyStruct& s) cil managed
{
.param [1]
.custom instance void System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = ( 01 00 00 00 )
// 程式碼大小 17 (0x11)
.maxstack 1
.locals init ([0] valuetype ConsoleApp2.MyStruct V_0)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldobj ConsoleApp2.MyStruct
IL_0007: stloc.0
IL_0008: ldloca.s V_0
IL_000a: call instance void ConsoleApp2.MyStruct::Request()
IL_000f: nop
IL_0010: ret
} // end of method Program::Test
將 MyStruct 宣告為 readonly,程式碼改變如下:
程式碼 3
class Program
{
static void Main(string[] args)
{
}
void Test(in MyStruct s)
{
s.Request();
}
}
public readonly struct MyStruct
{
private readonly int _y;
public int X { get; }
public MyStruct(int a)
{
X = a;
_y = a;
}
public void Request()
{ }
}
在Test方法就不再產生出臨時區域變數。
.method private hidebysig instance void Test([in] valuetype ConsoleApp2.MyStruct& s) cil managed
{
.param [1]
.custom instance void System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = ( 01 00 00 00 )
// 程式碼大小 9 (0x9)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.1
IL_0002: call instance void ConsoleApp2.MyStruct::Request()
IL_0007: nop
IL_0008: ret
} // end of method Program::Test
結語
struct-type 若是僅使用於 readonly field 和透過 in 參數修飾詞傳遞以及 readonly ref 之時,將它設計為 readonly struct 會比一般可變性的 strcut 來得有效能優勢。