ฉันเพิ่งเจอArraySegment<byte>ประเภทในขณะที่คลาสย่อยของMessageEncoderชั้นเรียน
ตอนนี้ฉันเข้าใจแล้วว่ามันเป็นเซ็กเมนต์ของอาร์เรย์ที่กำหนดใช้ค่าออฟเซ็ตไม่สามารถนับได้และไม่มีตัวสร้างดัชนี แต่ฉันยังไม่เข้าใจการใช้งาน ใครช่วยอธิบายด้วยตัวอย่างได้ไหม
ฉันเพิ่งเจอArraySegment<byte>ประเภทในขณะที่คลาสย่อยของMessageEncoderชั้นเรียน
ตอนนี้ฉันเข้าใจแล้วว่ามันเป็นเซ็กเมนต์ของอาร์เรย์ที่กำหนดใช้ค่าออฟเซ็ตไม่สามารถนับได้และไม่มีตัวสร้างดัชนี แต่ฉันยังไม่เข้าใจการใช้งาน ใครช่วยอธิบายด้วยตัวอย่างได้ไหม
คำตอบ:
ArraySegment<T>กลายเป็นประโยชน์มากขึ้นใน. NET 4.5 + และ. NET Coreเนื่องจากตอนนี้ใช้:
IList<T>ICollection<T>IEnumerable<T>IEnumerableIReadOnlyList<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
GetEnumeratorส่วนตัวอย่างอธิบายไม่ได้แต่หมายความว่าคุณถูกบังคับให้เลือกIEnumerable<T>(แปลงชกมวย) เพื่อเรียกสิ่งนี้ ฮึ
มันเป็นโครงสร้างทหารตัวน้อยที่ไม่ได้ทำอะไรเลยนอกจากเก็บข้อมูลอ้างอิงไปยังอาร์เรย์และเก็บช่วงดัชนี อันตรายเล็กน้อยโปรดระวังว่าจะไม่ทำสำเนาข้อมูลอาร์เรย์และไม่ทำให้อาร์เรย์ไม่เปลี่ยนรูปหรือแสดงความจำเป็นในการไม่เปลี่ยนรูปในทางใดทางหนึ่ง รูปแบบการเขียนโปรแกรมทั่วไปมากขึ้นคือเก็บหรือส่งอาร์เรย์และตัวแปรความยาวหรือพารามิเตอร์เช่นเดียวกับที่ทำในเมธอด. NET BeginRead (), String.SubString (), Encoding.GetString () ฯลฯ เป็นต้น
NET Framework ไม่ได้รับประโยชน์มากนักยกเว้นสิ่งที่ดูเหมือนว่าโปรแกรมเมอร์ Microsoft คนหนึ่งที่ทำงานบนเว็บซ็อกเก็ตและ WCF ชอบ ซึ่งน่าจะเป็นคำแนะนำที่เหมาะสมถ้าคุณชอบก็ใช้มัน มันทำ peek-a-boo ใน. NET 4.6 ซึ่งเป็นเมธอด MemoryStream.TryGetBuffer () ที่เพิ่มเข้ามาใช้ ต้องการมากกว่ามีสองoutข้อโต้แย้งที่ฉันคิด
โดยทั่วไปแล้วแนวคิดที่เป็นสากลมากขึ้นของชิ้นส่วนนั้นเป็นที่ต้องการของวิศวกรหลัก. NET เช่น Mads Torgersen และ Stephen Toub หลังเตะออกarray[:]ไวยากรณ์ข้อเสนอในขณะที่ที่ผ่านมาคุณจะเห็นสิ่งที่พวกเขาได้รับความคิดเกี่ยวกับในหน้านี้โรสลิน ฉันคิดว่าการได้รับการสนับสนุน CLR คือสิ่งที่เกิดขึ้นในท้ายที่สุด นี้เป็นงานที่ได้รับการคิดเกี่ยวกับการสำหรับ C # 7 รุ่น AFAIK ให้ตาของคุณในSystem.Slices
ปรับปรุง: ตายลิงก์นี้ส่งในรุ่น 7.2 เป็นช่วง
Update2: การสนับสนุนเพิ่มเติมใน C # เวอร์ชัน 8.0 พร้อมประเภท Range และ Index และวิธี Slice ()
ArraySegmentมีตัวสร้างดัชนีในขณะที่MemoryและSpanเงียบเกี่ยวกับเรื่องนี้
- การแบ่งส่วนบัฟเฟอร์สำหรับคลาส IO - ใช้บัฟเฟอร์เดียวกันสำหรับการดำเนินการอ่านและเขียนพร้อมกันและมีโครงสร้างเดียวที่คุณสามารถส่งผ่านอธิบายการดำเนินการทั้งหมดของคุณได้
- ตั้งค่าฟังก์ชัน - การพูดทางคณิตศาสตร์คุณสามารถแสดงชุดย่อยที่ต่อเนื่องกันโดยใช้โครงสร้างใหม่นี้ โดยพื้นฐานแล้วหมายความว่าคุณสามารถสร้างพาร์ติชันของอาร์เรย์ได้ แต่คุณไม่สามารถแสดงถึงราคาทั้งหมดและคู่ทั้งหมดได้ โปรดทราบว่าทีเซอร์โทรศัพท์ที่เสนอโดย The1 สามารถแก้ไขได้อย่างสวยงามโดยใช้การแบ่งพาร์ติชัน ArraySegment และโครงสร้างแบบต้นไม้ ตัวเลขสุดท้ายสามารถเขียนได้โดยการสำรวจความลึกของต้นไม้ก่อน นี่คงเป็นสถานการณ์ในอุดมคติในแง่ของหน่วยความจำและความเร็วที่ฉันเชื่อ
- มัลติเธรด - ขณะนี้คุณสามารถวางไข่หลายเธรดเพื่อทำงานบนแหล่งข้อมูลเดียวกันได้ในขณะที่ใช้อาร์เรย์ที่แบ่งส่วนเป็นเกตควบคุม ลูปที่ใช้การคำนวณแบบแยกส่วนสามารถทำฟาร์มได้อย่างง่ายดายซึ่งเป็นสิ่งที่คอมไพเลอร์ C ++ ล่าสุดเริ่มทำเป็นขั้นตอนการเพิ่มประสิทธิภาพโค้ด
- การแบ่งส่วน UI - จำกัด การแสดง UI ของคุณโดยใช้โครงสร้างแบบแบ่งส่วน ตอนนี้คุณสามารถจัดเก็บโครงสร้างที่แสดงหน้าข้อมูลที่สามารถนำไปใช้กับฟังก์ชันการแสดงผลได้อย่างรวดเร็ว สามารถใช้อาร์เรย์เดี่ยวที่ต่อเนื่องกันเพื่อแสดงมุมมองที่ไม่ต่อเนื่องหรือแม้กระทั่งโครงสร้างแบบลำดับชั้นเช่นโหนดใน TreeView โดยการแบ่งส่วนที่เก็บข้อมูลเชิงเส้นออกเป็นส่วนการรวบรวมโหนด
ในตัวอย่างนี้เราจะดูวิธีที่คุณสามารถใช้อาร์เรย์ดั้งเดิมคุณสมบัติออฟเซ็ตและจำนวนรวมถึงวิธีที่คุณสามารถวนซ้ำองค์ประกอบที่ระบุใน 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]);
}
}
}
i < segment.Offset + segment.Countผมเชื่อว่าคำสั่งเงื่อนไขของการห่วงควรจะเป็น
คลาส Wrapper คืออะไร? เพียงเพื่อหลีกเลี่ยงการคัดลอกข้อมูลไปยังบัฟเฟอร์ชั่วคราว
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);
}
Ouput:
3
4
3
4
IEnumerable<T>จากนั้นเพิ่ม IEnumeratorIEnumerable.GetEnumerator() { return GetEnumerator(); }
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,}
IList<T>ก็สงสารก็จำเป็นที่จะโยนมันทิ้งไป publicผมคาดว่าดัชนีจะเป็น
พูดง่ายๆก็คือมันจะอ้างอิงไปยังอาร์เรย์ช่วยให้คุณมีการอ้างอิงหลายรายการไปยังตัวแปรอาร์เรย์เดียวโดยแต่ละตัวมีช่วงที่แตกต่างกัน
ในความเป็นจริงมันช่วยให้คุณใช้และส่งผ่านส่วนต่างๆของอาร์เรย์ในรูปแบบที่มีโครงสร้างมากขึ้นแทนที่จะมีตัวแปรหลายตัวเพื่อเก็บดัชนีและความยาวเริ่มต้น นอกจากนี้ยังมีอินเทอร์เฟซการรวบรวมเพื่อให้ทำงานกับส่วนอาร์เรย์ได้ง่ายขึ้น
ตัวอย่างเช่นตัวอย่างโค้ดสองตัวอย่างต่อไปนี้ทำสิ่งเดียวกันหนึ่งรายการมี 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());
เห็นได้ชัดว่าข้อมูลโค้ดแรกเป็นที่ต้องการมากกว่าโดยเฉพาะเมื่อคุณต้องการส่งผ่านส่วนอาร์เรย์ไปยังฟังก์ชัน
ArraySegmentจะแจกแจงได้ใน. Net 4.5