不安全结构体中的只读数组字段

3
这是原始声明:

这是原始声明:

[StructLayout(LayoutKind.Explicit, Size = 16)]
public unsafe struct X
{
  [FieldOffset(0)] public ushort a;
  [FieldOffset(2)] public fixed byte b[14];
};

我希望将struct设为只读,但我不知道如何编写数组的getter。 我能想到的唯一解决方案是编写一个getter方法
[StructLayout(LayoutKind.Explicit, Size = 16)]
public unsafe struct X
{
  [FieldOffset(0)] private ushort a;
  [FieldOffset(2)] private fixed byte b[14];

  public ushort A { get { return a; } }
  public byte B(int i) { fixed (byte* p = b) { return p[i]; } }
};

有没有可能为b编写一个getter 属性而不是一个getter 方法

=== 更新 ===

我还想处理当存在多个数组字段的情况。 例如:

[StructLayout(LayoutKind.Explicit, Size = 24)]
public unsafe struct Y
{
  [FieldOffset(0)] private ushort a;
  [FieldOffset(2)] private fixed byte b[14];
  [FieldOffset(16)] private fixed byte c[8];

  public ushort A { get { return a; } }
  public byte B(int i) { fixed (byte* p = b) { return p[i]; } }
  public byte C(int i) { fixed (byte* p = c) { return p[i]; } }
};

是否可以编写获取bc属性的getter方法,而不是getter方法?我想编写y.B[i]y.C[i],而不是y.B(i)y.C(i)


你只应该在处理非托管代码互操作时使用这样的声明。此时,结构成员只读就不再有意义了。与之互操作的语言需要以这种方式声明,可能需要使用const - Hans Passant
@HansPassant 是的,我需要这个用于Interop代码。我有一个来自第三方非托管库的byte*,在添加偏移量后,我将其转换为指向类似不安全结构的指针。我只想要(1)防止我的代码用户覆盖原始的非托管数据,以及(2)修改getter内部的一些字段。因此,我将每个字段都设置为私有,并添加了getter。 - kol
永远不要将不安全的结构暴露给客户端代码。这是不安全的,也没有人喜欢打开这个选项。 - Hans Passant
@HansPassant 我需要这样做才能达到预定的性能。实际上,这个问题与这个问题有关:https://dev59.com/6GMm5IYBdhLWcg3whfSe - kol
2个回答

3

您可以使用索引器属性来访问特定索引处的数组。不幸的是,它需要在结构体本身而不是B上定义,但这应该提供您所需的内容:

[StructLayout(LayoutKind.Explicit, Size = 16)]
public unsafe struct X
{
    [FieldOffset(0)]
    private ushort a;
    [FieldOffset(2)]
    private fixed byte b[14];

    public ushort A { get { return a; } }
    public byte this [int i]
    {
        get 
        {
            byte b1;
            fixed (byte* b2 = b)
            {
                b1 = b2[i];
            }
            return b1;
        }
    }
 }; 

2
注意:可以简化为 fixed (byte* ptr = b) { return ptr[i]; } - 但本质上是一样的。 - Marc Gravell
+1 OK,但是我想要索引的不是X本身,而是它的字段b。假设我还有另一个数组字段c。我想同时索引b,如x.B[i],和c,如x.C[i],其中x的类型为X。 - kol
@Chris 我扩展了问题,包括当存在多个数组字段的情况。谢谢你的帮助! - kol
@MarcGravell 感谢您的建议,我简化了问题中的代码。 - kol

1

我找到了一个解决方案,它基于索引属性的思想:

[StructLayout(LayoutKind.Explicit, Size = 14)]
public struct YB
{
  [FieldOffset(0)] private fixed byte b[14];
  public byte this[int i] { get { fixed (byte* p = b) { return p[i]; } } }
}

[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct YC
{
  [FieldOffset(0)] private fixed byte c[8];
  public byte this[int i] { get { fixed (byte* p = c) { return p[i]; } } }
}

[StructLayout(LayoutKind.Explicit, Size = 24)]
public unsafe struct Y
{
  [FieldOffset(0)] private ushort a;
  [FieldOffset(2)] private YB b;
  [FieldOffset(16)] private YC c;

  public ushort A { get { return a; } }
  public YB B { get { return b; } }
  public YC C { get { return c; } }
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接