什么是使用ArraySegment <T>类?

我只是在子类化MessageEncoder类的时候碰到了ArraySegment<byte>types。

我现在明白,它是给定数组的一部分,需要一个偏移量,不是可枚举的,也没有索引器,但是我仍然无法理解它的用法。 有人可以请示例解释吗?

ArraySegment<T> 在.NET 4.5中变得更加有用,因为它现在实现了:

  • IList<T>
  • ICollection<T>
  • IEnumerable<T>
  • IEnumerable
  • IReadOnlyList<T>
  • IReadOnlyCollection<T>

而不是没有实现任何接口的.NET 4版本 。

这个类现在可以参与到LINQ的奇妙世界中,所以我们可以像查询内容那样执行通常的LINQ事情,颠倒内容而不影响原始数组,获取第一个项目,等等:

 var array = new byte[] { 5, 8, 9, 20, 70, 44, 2, 4 }; array.Dump(); var segment = new ArraySegment<byte>(array, 2, 3); segment.Dump(); // output: 9, 20, 70 segment.Reverse().Dump(); // output 70, 20, 9 segment.Any(s => s == 99).Dump(); // output false segment.First().Dump(); // output 9 array.Dump(); // no change 
  1. IO类的缓冲区分区 – 使用同一个缓冲区进行同时读写操作,并有一个可以传递的结构来描述整个操作。
  2. 设置函数 – 从math上讲,您可以使用这个新的结构来表示任何连续的子集。 这基本上意味着你可以创build数组的分区,但是你不能代表所有的可能性和所有的平均值。 请注意,The1提出的电话预告片可以使用ArraySegment分区和树结构进行优雅地解决。 最后的数字可以通过首先遍历树的深度写出来。 就内存和速度而言,这将是一个理想的情景。
  3. multithreading – 现在您可以产生多个线程来操作相同的数据源,同时使用分段arrays作为控制门。 使用离散计算的循环现在可以很容易地完成,最新的C ++编译器开始作为代码优化步骤。
  4. UI分段 – 使用分段结构限制您的UI显示。 您现在可以存储表示可快速应用于显示function的数据页面的结构。 通过将线性数据存储分割成节点集合段,可以使用单个连续数组来显示离散视图,甚至是层次结构,例如TreeView中的节点。

在这个例子中,我们看看如何使用原始数组,Offset和Count属性,以及如何循环ArraySegment中指定的元素。

 using System; class Program { static void Main() { // Create an ArraySegment from this array. int[] array = { 10, 20, 30 }; ArraySegment<int> segment = new ArraySegment<int>(array, 1, 2); // Write the array. Console.WriteLine("-- Array --"); int[] original = segment.Array; foreach (int value in original) { Console.WriteLine(value); } // Write the offset. Console.WriteLine("-- Offset --"); Console.WriteLine(segment.Offset); // Write the count. Console.WriteLine("-- Count --"); Console.WriteLine(segment.Count); // Write the elements in the range specified in the ArraySegment. Console.WriteLine("-- Range --"); for (int i = segment.Offset; i < segment.Count+segment.Offset; i++) { Console.WriteLine(segment.Array[i]); } } } 

ArraySegment结构 – 他们在想什么?

什么是包装类? 只是为了避免复制数据到时间缓冲区。

 public class SubArray<T> { private ArraySegment<T> segment; public SubArray(T[] array, int offset, int count) { segment = new ArraySegment<T>(array, offset, count); } public int Count { get { return segment.Count; } } public T this[int index] { get { return segment.Array[segment.Offset + index]; } } public T[] ToArray() { T[] temp = new T[segment.Count]; Array.Copy(segment.Array, segment.Offset, temp, 0, segment.Count); return temp; } public IEnumerator<T> GetEnumerator() { for (int i = segment.Offset; i < segment.Offset + segment.Count; i++) { yield return segment.Array[i]; } } } //end of the class 

例:

 byte[] pp = new byte[] { 1, 2, 3, 4 }; SubArray<byte> sa = new SubArray<byte>(pp, 2, 2); Console.WriteLine(sa[0]); Console.WriteLine(sa[1]); //Console.WriteLine(b[2]); exception Console.WriteLine(); foreach (byte b in sa) { Console.WriteLine(b); } 

输出继电器:

 3 4 3 4 

这是一个微不足道的小战士结构,除了保留对数组的引用并存储索引范围外, 有一点危险,要小心它不会复制数组的数据,也不能以任何方式使数组不变或表示对不变性的需要。 更典型的编程模式是只保留或传递数组和长度variables或参数,如在.NET BeginRead()方法,String.SubString(),Encoding.GetString()等中完成。

它在.NET框架中没有得到太多的使用,除了看起来像一个特定的微软程序员在web套接字上工作,而WCF喜欢它。 这可能是适当的指导,如果你喜欢它然后使用它。 它确实在.NET 4.6中做了一个窥探,添加的MemoryStream.TryGetBuffer()方法使用它。 我首先假设有两个out参数。

一般来说, 切片的普遍概念在Mads Torgersen和Stephen Toub等.NET主要工程师的愿望清单中很高。 后者在前面踢了array[:]语法提议,你可以看到他们在这个Roslyn页面中一直在想什么。 我假设获得CLR支持是最终取决于的。 对于C#版本7 afaik,我们正在积极考虑这个问题,请注意System.Slices 。

ArraySegment比你想像的更有用。 尝试运行下面的unit testing,并准备惊讶!

  [TestMethod] public void ArraySegmentMagic() { var arr = new[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; var arrSegs = new ArraySegment<int>[3]; arrSegs[0] = new ArraySegment<int>(arr, 0, 3); arrSegs[1] = new ArraySegment<int>(arr, 3, 3); arrSegs[2] = new ArraySegment<int>(arr, 6, 3); for (var i = 0; i < 3; i++) { var seg = arrSegs[i] as IList<int>; Console.Write(seg.GetType().Name.Substring(0, 12) + i); Console.Write(" {"); for (var j = 0; j < seg.Count; j++) { Console.Write("{0},", seg[j]); } Console.WriteLine("}"); } } 

你看,你所要做的就是将一个ArraySegment投射到IList上,它将完成你所期望的所有事情。 注意这个types仍然是ArraySegment,尽pipe它的行为像一个普通的列表。

OUTPUT:

 ArraySegment0 {0,1,2,} ArraySegment1 {3,4,5,} ArraySegment2 {6,7,8,}