Да, это так.
Давайте рассмотрим образец
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
Поскольку нет необходимости распаковывать ссылку, нет Идентификатор инструкция.
Позвольте go для исчерпывающего ответа
Давайте посмотрим 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 инструкция.