思考ldind指令对于内置结构不是必需的,而对修改后的参数的数组索引器访问是不好的?

问题描述 投票:0回答:1

首先放开数组。

代码

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。

代码

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原始对象可以修改其状态吗?

立即查询

这是一些预算功能,或者在这种情况下也有理由制作防御性副本吗?

c# readonly cil defensive-copy in-parameters
1个回答
1
投票

是,是。

让我们考虑示例

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指令。

© www.soinside.com 2019 - 2024. All rights reserved.