我在ArraySegment<byte>
类的子类化时遇到了MessageEncoder
类型。
我现在明白它是给定数组的一部分,取一个偏移,不可枚举,并且没有索引器,但我仍然无法理解它的用法。有人可以用一个例子解释一下吗?
答案 0 :(得分:44)
ArraySegment<T>
已成为现在实施的lot more useful in .NET 4.5:
IList<T>
ICollection<T>
IEnumerable<T>
IEnumerable
IReadOnlyList<T>
IReadOnlyCollection<T>
而不是实现任何接口的.NET 4 version。
该类现在能够参与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 :(得分:22)
- IO类的缓冲区分区 - 同时使用相同的缓冲区 读写操作并有一个 您可以传递的单一结构 描述了你的整个操作。
- 设置功能 - 从数学上讲,您可以代表任何功能 使用这个新的连续子集 结构体。这基本上意味着你 可以创建数组的分区, 但你不能代表所有的赔率 和所有的乐趣。注意手机 The1提出的预告片可能有 优雅地解决了使用 ArraySegment分区和树 结构体。最终的数字可以 已经通过遍历写出来了 树的深度第一。这会有 就此而言,这是一个理想的情景 记忆和速度我相信。
- 多线程 - 您现在可以生成多个线程来操作 使用分段时的相同数据源 数组作为控制门。循环 现在可以使用离散计算 什么东西很容易养殖 最新的C ++编译器 开始做代码优化 步。
- UI细分 - 使用细分限制您的UI显示 结构。你现在可以存储 表示数据页面的结构 可以很快应用到 显示功能。单个连续 可以使用数组来显示 离散视图,甚至是分层视图 结构,如a中的节点 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]);
}
}
}
答案 2 :(得分:18)
这是一个微不足道的小士兵结构,除了保持对数组的引用并存储索引范围之外什么都不做。有点危险,请注意它不会复制数组数据,也不会以任何方式使数组不可变或表达对不可变性的需求。更典型的编程模式是保持或传递数组和长度变量或参数,就像在.NET BeginRead()方法,String.SubString(),Encoding.GetString()等中完成的那样。 / p>
它在.NET Framework中没有多大用处,除了看起来像一个特定的Microsoft程序员在Web套接字和WCF喜欢它。这可能是正确的指导,如果你喜欢它然后使用它。它确实在.NET 4.6中做了一个嘘声,添加的MemoryStream.TryGetBuffer()方法使用它。首选我假设有两个out
参数。
一般而言, slices 这个更普遍的概念在主要的.NET工程师的愿望清单中很重要,如Mads Torgersen和Stephen Toub。后者在不久前启动了array[:]
语法提案,您可以在this Roslyn page中看到他们一直在考虑的内容。我认为获得CLR支持是最终取决于它的原因。对于C#版本7 afai,我们正在积极考虑这一点,请密切关注System.Slices。
更新:死链接,在版本7.2中以Span的形式发布。
Update2:使用范围和索引类型以及Slice()方法在C#8.0版中提供更多支持。
答案 3 :(得分:7)
什么是包装类?只是为了避免将数据复制到临时缓冲区。
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
答案 4 :(得分:5)
ArraySegment比您想象的更有用。尝试运行以下单元测试并准备好惊讶!
[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,它将完成你可能期望它做的所有事情。请注意,该类型仍然是ArraySegment,即使它的行为类似于普通列表。
输出:
ArraySegment0 {0,1,2,}
ArraySegment1 {3,4,5,}
ArraySegment2 {6,7,8,}
答案 5 :(得分:3)
简单来说:它保持对数组的引用,允许您对单个数组变量进行多次引用,每个变量都有不同的范围。
实际上,它可以帮助您以更结构化的方式使用和传递数组的各个部分,而不是使用多个变量来保存起始索引和长度。它还提供了集合接口,可以更轻松地使用数组部分。
例如,以下两个代码示例执行相同的操作,一个使用ArraySegment,另一个不使用:
byte[] arr1 = new byte[] { 1, 2, 3, 4, 5, 6 };
ArraySegment<byte> seg1 = new ArraySegment<byte>(arr1, 2, 2);
MessageBox.Show((seg1 as IList<byte>)[0].ToString());
和
byte[] arr1 = new byte[] { 1, 2, 3, 4, 5, 6 };
int offset = 2;
int length = 2;
byte[] arr2 = arr1;
MessageBox.Show(arr2[offset + 0].ToString());
显然,首选代码段是首选,特别是当您想将数组段传递给函数时。