如何在没有克隆的情况下获取子数组

时间:2015-07-17 03:38:09

标签: c#

我知道在C#中,我们总是可以使用Array.Copy()方法获取给定数组的子数组。但是,这将消耗更多的内存和处理时间,这在只读情况下是不必要的。例如,我正在编写一个重负载网络程序,它经常与集群中的其他节点交换消息。每条消息的前20个字节是消息头,而其余字节构成消息体。因此,我将接收到的原始消息分成头字节数组和主体字节数组,以便分别处理它们。但是,这显然会消耗双倍的内存和额外的时间。在C中,我们可以轻松地使用指针并为其指定偏移量来访问数组的不同部分。 例如,在C语言中,如果我们有char a[] = "ABCDEFGHIJKLMN",我们可以声明char* ptr = a + 3来表示数组DEFGHIJKLMN

有没有办法在C#中实现这个目标?

3 个答案:

答案 0 :(得分:5)

您可能对ArraySegmentsunsafe感兴趣。

ArraySegments分隔一维数组的一部分。

Check ArraySegments in action

ArraySegments用法示例:

 int[] array = { 10, 20, 30 };

 ArraySegment<int> segment = new ArraySegment<int>(array, 1, 2);
 // The segment contains offset = 1, count = 2 and range = { 20, 30 }

Unsafe定义了一个可以使用指针的不安全上下文。

不安全的用法示例:

    int[] a = { 4, 5, 6, 7, 8 };

    unsafe
    {
        fixed (int* c = a)
        {
            // use the pointer
        }
    }

答案 1 :(得分:1)

首先,您必须将此视为过早优化。

但如果您确定需要,可以使用多种方法来减少内存消耗:

1)您可以使用Flyweight模式https://en.wikipedia.org/wiki/Flyweight_pattern来汇集重复的资源。

2)您可以尝试使用不安全指令和手动指针管理。

3)您可以切换到C以获得此功能,只需从C#程序中调用本机代码即可。

根据我的经验,短期对象的内存消耗不是一个大问题,我之后只需用flyweight模式和配置文件应用程序编写代码。

答案 2 :(得分:0)

假设你在C#中有一个Message包装类?为什么不在它上面添加一个名为header的属性,返回前20个字节。

如果你在内存数组中有整个初始数组,你可以使用skip和上面的Jonathon Reinhart建议轻松完成这个,但听起来你可能在网络流中有它,这意味着属性可能有点通过从流中读取最初的20个字节来实现更多功能。

有些事情:

class Message
{
    private readonly Stream _stream;
    private byte[] _inMemoryBytes;

    public Message(Stream stream)
    {
        _stream = stream;
    }

    public IEnumerable<byte> Header
    {
        get
        {
            if (_inMemoryBytes.Length >= 20)
                return _inMemoryBytes.Take(20);

            _stream.Read(_inMemoryBytes, 0, 20);
            return _inMemoryBytes.Take(20);
        }
    }

    public IEnumerable<byte> FullMessage
    {
        get
        {
            // Read and return the whole message. You might want amend to data already read.
        }
    }
}