简体   繁体   English

在C#中将子数组作为引用

[英]Getting subarray as reference in C#

I have a large number of functions accepting input of sub-arrays (let's say, string) in a read-only way. 我有大量的函数以只读方式接受子数组的输入(比方说,字符串)。

I used Array.Copy (C++ memmove equivalent from MSDN) as a temporary workaround, but it comes to a serious bottleneck on running speed. 我使用Array.Copy (C ++ memmove等效于MSDN)作为临时解决方法,但它遇到了运行速度的严重瓶颈。 Is there any function I can get a sub-array, let's say [4~94] inside [0~99], such that it can be passed to a function x(array[]) as a reference where inside x the array is defined by [0~90]? 有没有任何函数我可以得到一个子数组,让我们说[4~94]在[0~99]内部,这样就可以传递给function x(array[])作为参考,其中x是数组的内部由[0~90]定义?

Unfortunately, arrays don't play nicely with partitioning. 不幸的是,数组不能很好地进行分区。 The only way to get a sub-array is by creating a copy of the original array, which is where the bottleneck probably is. 获取子数组的唯一方法是创建原始数组的副本,这可能是瓶颈所在。

If you can modify your functions to take IEnumerable parameters instead of arrays, you can do this easily with LINQ: 如果你可以修改你的函数来获取IEnumerable参数而不是数组,你可以使用LINQ轻松完成:

string[] values = { "foo", "bar", "baz", "zap" };
IEnumerable<string> subset = values.Skip(1).Take(2);

You could also look into ArraySegment , but this would (again) require changes to your functions' parameter types. 您还可以查看ArraySegment ,但这会(再次)需要更改函数的参数类型。

string[] values = { "foo", "bar", "baz", "zap" };
ArraySegment<string> segment = new ArraySegment<string>(values, 1, 2);

There is no built-in support for this in C#. 在C#中没有内置的支持。 You can pass by reference an individual element in an array, but not an address of an array segment that could then be interpreted as a 0-based array in managed code. 您可以通过引用传递数组中的单个元素,但不能传递数组段的地址,然后可以在托管代码中将其解释为基于0的数组。

The obvious solution is to pass an offset and length along with the array. 显而易见的解决方案是将偏移量和长度与数组一起传递。 You can make this a bit less painful by wrapping the array in an IReadOnlyList<T> implementation that encapsulates that for you. 通过将数组包装在为您封装的IReadOnlyList<T>实现中,您可以IReadOnlyList<T>这种IReadOnlyList<T> For example: 例如:

class SubsetList<T> : IReadOnlyList<T>
{
    private readonly IReadOnlyList<T> _list;
    private readonly int _offset = offset;
    private readonly int _length = length;

    public SubsetList(IReadOnlyList<T> list, int offset, int length)
    {
         _list = list;
         _offset = offset;
         _length = length;
    }

    public int Count { get { return _length; } }

    public T this[int index]
    {
        get { return _list[offset + index]; }
    }

    public IEnumerator<T> GetEnumerator()
    {
        for (int i = _offset; i < _offset + _length; i++)
        {
            yield return _list[i];
        }
    }

    private IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

Note that the above is not really needed, as it turns out .NET has (and has had since .NET 2.0) the ArraySegment<T> struct, which does the above and more. 请注意,上面并不是真正需要的,因为事实证明.NET已经(并且已经有.NET 2.0)的ArraySegment<T>结构,它完成了上述和更多。 But prior to .NET 4.0, it seems it didn't implement the features that would make it transparent to use (such as interface implementations and indexers). 但在.NET 4.0之前,它似乎没有实现使其透明使用的功能(例如接口实现和索引器)。

So I offer the above as an alternative for those so-constrained. 因此,我提供上述内容作为那些受限制的人的替代方案。 Note that IReadOnlyList<T> is itself new to .NET 4.5, so to use the above with prior versions of .NET, change that to IList<T> , and then implement all of the other members of the interface with a simple throw new NotSupportedException() (except possibly the setter for the indexer). 请注意, IReadOnlyList<T>本身是.NET 4.5的新手,因此要将上述版本与.NET的先前版本一起使用,请将其更改为IList<T> ,然后使用简单的throw new NotSupportedException()实现该接口的所有其他成员throw new NotSupportedException() (可能是索引器的setter除外)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM