代码
void Do1(in int[] ints)
{
inty[0] = 0;
}
void Do2(int[] ints)
{
inty[0] = 0;
}
CIL
.method private hidebysig
instance void Do1 (
[in] int32[]& inty
) cil managed
{
.param [1]
.custom instance void [System.Runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x2270
// Code size 6 (0x6)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldind.ref
IL_0002: ldc.i4.0
IL_0003: ldc.i4.0
IL_0004: stelem.i4
IL_0005: ret
} // end of method DefensiveCopyTest::Do1
.method private hidebysig
instance void Do2 (
int32[] inty
) cil managed
{
// Method begins at RVA 0x2277
// Code size 5 (0x5)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldc.i4.0
IL_0002: ldc.i4.0
IL_0003: stelem.i4
IL_0004: ret
} // end of method DefensiveCopyTest::Do2
Never use mutable structs as in in argument段中声明防御性复制的原因是Get访问器可以修改对象的状态。我相信这并不是数组索引器访问的乐趣。
代码
int Do1(in int num)
{
var n = num;
return n;
}
int Do2(int num)
{
var n = num;
return n;
}
CIL
.method private hidebysig
instance int32 Do1 (
[in] int32& num
) cil managed
{
.param [1]
.custom instance void [System.Runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x227d
// Code size 3 (0x3)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldind.i4
IL_0002: ret
} // end of method DefensiveCopyTest::Do1
.method private hidebysig
instance int32 Do2 (
int32 num
) cil managed
{
// Method begins at RVA 0x2281
// Code size 2 (0x2)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ret
} // end of method DefensiveCopyTest::Do2
情况非常相似。这次ldind.i4创建防御副本。再次访问.NET原始对象可以修改其状态吗?
这是一些预算功能,或者在这种情况下也有理由制作防御性副本吗?
是,是。
让我们考虑示例
ref readonly int Do1(in int num)
{
var n = num;
return ref num;
}
.method private hidebysig
instance int32& modreq([System.Runtime]System.Runtime.InteropServices.InAttribute) Do1 (
[in] int32& num
) cil managed
{
.param [0]
.custom instance void [System.Runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
01 00 00 00
)
.param [1]
.custom instance void [System.Runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x227d
// Code size 2 (0x2)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ret
} // end of method DefensiveCopyTest::Do1
因为不需要解压缩引用,所以没有Idind指令。
让我们看一下类似MS的示例
void DoThingsWithPoint3D(in Point3D point1, in Point3D point2)
{
double xDifference = point1.X - point2.X;
double yDifference = point1.Y - point2.Y;
double zDifference = point1.Z - point2.Z;
}
struct Point3D
{
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
}
.method private hidebysig
instance void DoThingsWithPoint3D (
[in] valuetype StaticLocalFunction.DefensiveCopyTest/Point3D& point1,
[in] valuetype StaticLocalFunction.DefensiveCopyTest/Point3D& point2
) cil managed
{
.param [1]
.custom instance void [System.Runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
01 00 00 00
)
.param [2]
.custom instance void [System.Runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x22a0
// Code size 43 (0x2b)
.maxstack 8
IL_0000: ldarg.1
IL_0001: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_X()
IL_0006: pop
IL_0007: ldarg.2
IL_0008: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_X()
IL_000d: pop
IL_000e: ldarg.1
IL_000f: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_Y()
IL_0014: pop
IL_0015: ldarg.2
IL_0016: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_Y()
IL_001b: pop
IL_001c: ldarg.1
IL_001d: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_Z()
IL_0022: pop
IL_0023: ldarg.2
IL_0024: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_Z()
IL_0029: pop
IL_002a: ret
} // end of method DefensiveCopyTest::DoThingsWithPoint3D
通过ldarg指令来确保防御性副本。
void DoThingsWithPoint3D(Point3D point1, Point3D point2)
{
double xDifference = point1.X - point2.X;
double yDifference = point1.Y - point2.Y;
double zDifference = point1.Z - point2.Z;
}
.method private hidebysig
instance void DoThingsWithPoint3D (
valuetype StaticLocalFunction.DefensiveCopyTest/Point3D point1,
valuetype StaticLocalFunction.DefensiveCopyTest/Point3D point2
) cil managed
{
// Method begins at RVA 0x22cc
// Code size 49 (0x31)
.maxstack 8
IL_0000: ldarga.s point1
IL_0002: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_X()
IL_0007: pop
IL_0008: ldarga.s point2
IL_000a: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_X()
IL_000f: pop
IL_0010: ldarga.s point1
IL_0012: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_Y()
IL_0017: pop
IL_0018: ldarga.s point2
IL_001a: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_Y()
IL_001f: pop
IL_0020: ldarga.s point1
IL_0022: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_Z()
IL_0027: pop
IL_0028: ldarga.s point2
IL_002a: call instance int32 StaticLocalFunction.DefensiveCopyTest/Point3D::get_Z()
IL_002f: pop
IL_0030: ret
} // end of method DefensiveCopyTest::DoThingsWithPoint3D
为了读取,调用了ldarga.s指令。