2010-10-12 41 views
2

我想创建一个属性,将从我的字节数组(字节[]),使指针(字节*),这的确行得通,但是每当我修改这个返回的指针,我的字节数组不会被修改,这是我想要使用的一段代码。一个字节[]到字节*属性

public unsafe class PacketWriter 
{ 
    private readonly byte[] _packet; 
    private int _position; 

    public byte* Pointer 
    { 
     get 
     { 
      fixed (byte* pointer = _packet) 
       return pointer; 
     } 
    } 

    public PacketWriter(int packetLength) 
    { 
     _packet = new byte[packetLength]; 
    } 

    //An example function 
    public void WriteInt16(short value) 
    { 
     if (value > Int16.MaxValue) 
      throw new Exception("PacketWriter: You cannot write " + value + " to a Int16."); 
     *((short*)(Pointer + _position)) = (short) value; 
     _position += 2; 
    } 

    //I would call this function to get the array. 
    public byte[] GetPacket 
    { 
     get { return _packet; } 
    } 
} 

而且,我知道我可以简单地删除属性,并把函数内部的代码,这可能会工作,但是我试图找出一种方法使用属性来做到这一点 - 除非这会降低性能在这种情况下,请让我知道。

+1

你为什么要这样做,而不是简单地使用普通数组? – 2010-10-12 13:52:14

+1

当垃圾收集器移动阵列时,此代码将炸弹或无声地破坏堆。在属性获取器返回后,该数组不再固定。赔率低但不为零。 – 2010-10-12 15:09:16

+0

它只是让我感到你正在编写可能用于网络通信的代码,你可能想要保留网络字节顺序。在这种情况下,我建议在MemoryStream上使用BinaryReader和BinaryWriter,因为这些可以指定编码的字节顺序。您提出的代码和BitConverter都将使用平台端到端。 – 2010-10-14 03:09:04

回答

6

在这里使用指针(在C#中)是毫无意义的。

请注意,如果您有

public byte[] Data { get { return _packet; } } 

更换Pointer财产您必须返回参考的字节数组的属性,它可以让你做同样的编辑在阵列中的一个指针,而无需在任何时候复制数组。

而另一条建议,在你Write16,使用:

byte[] data = BitConverter.GetBytes(value); 
data.CopyTo(_packet, _positiion); 
_position += data.Length; 
+0

+1,BitConverter是将字节等价物写入数组(它使用平台排序)的最干净和最平台安全的方式。 – 2010-10-12 14:43:10

2

当您的控件离开fixed(并且它在返回后立即执行)后,您的对象不再被锁定。所以它只在fixed内有效

+0

@Andrey,有没有不同的方式来实现我的目标? – Basser 2010-10-12 13:41:46

+0

@Basser使用C++ :)你应该在功能范围内使用'fixed'。财产访问将不起作用。我没有理由在这里使用'byte *',指针在C#中是例外的,并且需要特殊情况。这一个绝对不是。 – Andrey 2010-10-12 13:44:21

+0

@Basser,你的目标是什么?你想用指针做什么? – testalino 2010-10-12 13:45:24

0

如果你正在处理被管理的内存,那么是的,你必须限制它到fixed块。

看起来你正在使用大量的指针处理,我的问题是为什么你需要一个托管内存?只需使用Marshal.AllocHGlobal()分配一些非托管内存,然后将其作为指针公开。你只需要确保你在Dispose()中发布它。

2

不要让指针。 你在抢先优化你的代码。为了举一个例子,我在C#中为我正在开发的一个项目编写了一个PNG解码器,而不是假设这个瓶颈,我编写了代码来使管理数据结构变得微不足道,并且相当关注I/O和数据运动。在对代码进行基准测试时,瓶颈不在数据移动或I/O中,而是在Paeth预测器中 - 计算以像素为单位进行(详细信息请参见here)。

首先编写可读和可维护的代码,然后查看瓶颈位置。你可以随时重构它。

1

在.NET中对数组索引非常有效;抖动产生的机器代码基本上等同于通过指针算术访问。如果您编写使用位掩码和位移来生成写入数组的字节值的等效代码,它可能会比尝试使用不安全的代码更快。钉扎的开销将远远高于一些廉价的位掩蔽操作。如果你真的,绝对需要节省几个时钟周期(以降低可维护性为代价的昂贵代价),要么在C++中创建一个非托管DLL来处理高性能需求,要么编写完全在非托管内存中操作的纯不安全代码与元帅。事实上,元帅已经有了一个可以使用的WriteInt16方法。然而,封送到托管内存的开销会比较高,但是(比位掩码高得多),所以这只有在您在内部循环中编写大量内存并且正在执行其他操作时才有用除了简单的复制操作(因为无论如何它都必须复制到托管内存来编组)。