开发者

IEnumerable<T> ToArray usage - Is it a copy or a pointer?

开发者 https://www.devze.com 2022-12-28 02:46 出处:网络
I am parsing an arbitrary length byte array that is going to be passed around to a few different layers of parsing. Each parser creates a Header and a Packet payload just like any ordinary encapsulati

I am parsing an arbitrary length byte array that is going to be passed around to a few different layers of parsing. Each parser creates a Header and a Packet payload just like any ordinary encapsulation.

My problem lies in how the encapsulation holds its packet byte array payload. Say I have a 100 byte array with three levels of encapsulation. Three packet objects will be created and I want to set the payload of these packets to the corresponding position in the byte array of the packet.

For example, let's say the payload size is 20 for all levels, then imagine it has a public byte[] Payload on each object. However, the problem is that this byte[] Payload is a copy of the original开发者_StackOverflow中文版 100 bytes, so I'm going to end up with 160 bytes in memory instead of 100.

If it were in C++, I could just easily use a pointer - however, I'm writing this in C#.

So I created the following class:

public class PayloadSegment<T> : IEnumerable<T>
{
    public readonly T[] Array;
    public readonly int Offset;
    public readonly int Count;

    public PayloadSegment(T[] array, int offset, int count)
    {
        this.Array = array;
        this.Offset = offset;
        this.Count = count;
    }

    public T this[int index]
    {
        get
        {
            if (index < 0 || index >= this.Count)
                throw new IndexOutOfRangeException();
            else
                return Array[Offset + index];
        }
        set
        {
            if (index < 0 || index >= this.Count)
                throw new IndexOutOfRangeException();
            else
                Array[Offset + index] = value;
        }
    }

    public IEnumerator<T> GetEnumerator()
    {
        for (int i = Offset; i < Offset + Count; i++)
            yield return Array[i];
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        IEnumerator<T> enumerator = this.GetEnumerator();
        while (enumerator.MoveNext())
        {
            yield return enumerator.Current;
        }
    }
}

This way I can simply reference a position inside the original byte array but use positional indexing. However, if I do something like:

 PayloadSegment<byte> something = new PayloadSegment<byte>(someArray, 5, 10);
 byte[] somethingArray = something.ToArray();

Will the somethingArray be a copy of the bytes, or a reference to the original PayloadSegment (which in turn is a reference to the original byte array)?

EDIT: Actually after rethinking this, can't I simply use a new MemoryStream(array, offset, length)?


The documentation for the Enumerable.ToArray extension method doesn't specifically mention what it does when it's passed a sequence that happens to already be an array. But a simple check with .NET Reflector reveals that it does indeed create a copy of the array.

It is worth noting however that when given a sequence that implements ICollection<T> (which Array does) the copy can be done much faster because the number of elements is known up front so it does not have to do dynamic resizing of the buffer such as List<T> does.


There is a very strong practice which suggests that calling "ToArray" on an object should return a new array which is detached from anything else. Nothing that is done to the original object should affect the array, and nothing which is done to the array should affect the original object. My personal preference would have been to call the routine "ToNewArray", to make explicit that each call will return a different new array.

A few of my classes have an "AsReadableArray", which returns an array which may or may not be attached to anything else. The array won't change in response to manipulations to the original object, but it's possible that multiple reads yielding the same data (which they often will) will return the same array. I really wish .net had an ImmutableArray type, supporting the same sorts of operations as String [a String, in essence, being an ImmutableArray(Of Char)], and a ReadableArray abstract type (from which both Array and ImmutableArray would inherit). I doubt such a thing could be squeezed into .Net 5.0, but it would allow a lot of things to be done much more cleanly.


It is a copy. When you call a To<Type> method, it creates a copy of the source element with the target Type


Because byte is a value type, the array will hold copies of the values, not pointers to them.
If you need the same behavior as an reference type, it is best to create a class that holds the byte has a property, and may group other data and functionality.


It's a copy. It would be very unintuitive if I passed something.ToArray() to some method, and the method changed the value of something by changing the array!

0

精彩评论

暂无评论...
验证码 换一张
取 消