【问题标题】:Read-only array field in unsafe struct不安全结构中的只读数组字段
【发布时间】:2013-08-13 15:58:29
【问题描述】:

这是原始声明:

[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 property 而不是一个 getter method

=== 更新 ===

我也想处理多个数组字段的情况。例如:

[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]; } }
};

是否可以为 b 和 c 编写一个 getter properties 而不是 getter methods?我想写y.B[i]y.C[i] 而不是y.B(i)y.C(i)

【问题讨论】:

  • 您应该只对非托管代码互操作使用这样的声明。那时,让结构成员只读不再意味着什么。您与之交互的语言需要以这种方式声明,可能使用 const.
  • @HansPassant 是的,我需要这个用于互操作代码。我有一个来自 3rd 方非托管库的字节*,在添加偏移量后,我将其转换为指向类似不安全结构的指针。我只想(1)阻止我的代码用户覆盖原始的非托管数据,以及(2)修改getter中的一些字段。所以我将每个字段设为私有并添加了 getter。
  • 永远不要将不安全的结构暴露给客户端代码。这是不安全的,没有人喜欢打开这个选项。
  • @HansPassant 我需要这样做才能达到规定的性能。实际上这个问题与这个问题有关:stackoverflow.com/questions/17549123/…

标签: c# arrays properties getter unsafe


【解决方案1】:

您可以使用索引器属性来访问特定索引处的数组。不幸的是,它需要在结构本身而不是 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;
        }
    }
 }; 

【讨论】:

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

我找到了一个解决方案,就是基于indexed properties的思路:

[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; } }
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-07
    • 2011-01-22
    • 1970-01-01
    • 2012-08-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多