在C#中引用数组的一部分

时间:2010-08-30 19:22:45

标签: c# arrays reference copy

我得到的数组包含一些数据,比如标题和真实数据。我需要将数组中包含的数据传递给方法,但我绝对希望避免将其复制到另一个数组。

我想到了像ArraySegment这样的东西,但似乎在我的情况下不起作用(或者我错了?)。

那么,如何将一个数组的一部分传递给一个方法,因为它本身就是一个数组?

感谢您的回复!

干杯

5 个答案:

答案 0 :(得分:6)

SkipTake

var subArray = array.Skip(5).Take(10);

答案 1 :(得分:5)

如果您想坚持只使用基本数组(即int []数字),那么最有效的方法是让您的函数直接采用偏移/计数

有很多IO功能可以做类似的事情:

readData(data, 0, 4);

string readData(byte [] buffer, int offset, int length)

另一种选择是使用IEnumberable< T>并使用skip / take

readData(data.Skip(0).Take(4));

string readData(IEnumerable<byte> buffer)

重要的是要记住,在c#中你没有处理指针,你正在处理对象。

答案 2 :(得分:4)

我和Jon Skeet的想法完全相同:在T[]周围实现一个包装器,它通过索引提供随机访问,自动处理索引访问的调整。

我刚才快速实施了一个快速实现(跳过这个答案的底部进行简短的演示):

public struct ArrayFragment<T> : IList<T>
{
    private T[] _source;
    private int _start;
    private int _count;

    public ArrayFragment(T[] source, int start, int count)
    {
        if (source == null)
        {
            throw new ArgumentNullException("source");
        }
        if (start < 0 || start >= source.Length)
        {
            throw new ArgumentOutOfRangeException("start");
        }
        if (count > source.Length - start)
        {
            throw new ArgumentOutOfRangeException("count");
        }

        _source = source;
        _start = start;
        _count = count;
    }

    public T this[int index]
    {
        get { return _source[_start + index]; }
    }

    public int Count
    {
        get { return _count; }
    }

    public bool Contains(T value)
    {
        int index = Array.IndexOf(_source, value, _start, _count);
        return index != -1;
    }

    public void CopyTo(T[] destination, int index)
    {
        Array.Copy(_source, _start, destination, index, _count);
    }

    public int IndexOf(T value)
    {
        int index = Array.IndexOf(_source, value, _start, _count);
        return index != -1 ? index - _start : -1;
    }

    public IEnumerator<T> GetEnumerator()
    {
        for (int i = 0; i < _count; ++i)
        {
            yield return _source[_start + i];
        }
    }

    #region Explicit Interface Implementation

    // a bunch of explicitly implemented IList<T> members
    // that all throw a NotSupportedException

    #endregion
}

这是一个演示:

int[] numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

try
{
    var fragment = new ArrayFragment<int>(numbers, 2, 5);

    Console.WriteLine("Iterating using foreach: ");
    foreach (int number in fragment)
    {
        Console.WriteLine(number);
    }

    Console.WriteLine("Iterating using for: ");
    for (int i = 0; i < fragment.Count; ++i)
    {
        Console.WriteLine(fragment[i]);
    }

    Console.WriteLine("Index of 4: {0}", fragment.IndexOf(4));
    Console.WriteLine("Index of 1: {0}", fragment.IndexOf(1));
    Console.WriteLine("Index of 9: {0}", fragment.IndexOf(9));
    Console.WriteLine("Index of 7: {0}", fragment.IndexOf(7));
}
catch (Exception ex)
{
    Console.WriteLine(ex.ToString());
}

Console.ReadLine();

输出:

Iterating using foreach:
3
4
5
6
7
Iterating using for:
3
4
5
6
7
Index of 4: 1
Index of 1: -1
Index of 9: -1
Index of 7: 4

答案 3 :(得分:3)

从我所看到的,你有两个选择:

  1. 修改您正在调用的方法(如果您有选项)。您可以让它接受一个数组,一个起始索引和一个结束索引,而不仅仅是接受一个数组(或IEnumerable)。

  2. 传入一个IEnumerable对象,而不是传递一个数组,该对象枚举数组中所需的范围(不需要复制数组中的项)。一种方法是:

  3. var slice = someArray.Skip(startIndex).Take(endIndex - startIndex); 
    

答案 4 :(得分:0)

一种选择是在以不可变的方式实现ReadOnlyCollection<T>方面实现像 IList<T>这样的东西,但在现有集合中将其作为“视图”公开,转移任何索引都适当地访问(并有适当的计数等)。

它可能是一个非常方便的包装类。然后,您可以修改方法以接受适当的IList<T>而不是数组。