פתרון תצוגות ובעלות על buffer¶
ה־Cursor בודק את האורך שנותר לפני שינוי המיקום. ה־TryTake דוחה גם אורך שלילי, כך שלא נוצרת אפשרות לחזור אחורה דרך אותו API.
using System.Buffers.Binary;
var cursor = new Cursor(new byte[] { 2, 0, 0, 0, 7, 8 });
Console.WriteLine(cursor.TryReadUInt32(out uint length));
Console.WriteLine(cursor.TryTake((int)length, out var data));
Console.WriteLine(data[1]);
int before = cursor.Position;
Console.WriteLine(cursor.TryReadUInt32(out _));
Console.WriteLine(before == cursor.Position);
ref struct Cursor(ReadOnlySpan<byte> input)
{
private readonly ReadOnlySpan<byte> input = input;
public int Position { get; private set; }
public bool TryReadUInt32(out uint value)
{
value = 0;
if (input.Length - Position < 4) return false;
value = BinaryPrimitives.ReadUInt32LittleEndian(input[Position..]);
Position += 4;
return true;
}
public bool TryTake(int length, out ReadOnlySpan<byte> value)
{
value = default;
if (length < 0 || length > input.Length - Position) return false;
value = input.Slice(Position, length);
Position += length;
return true;
}
}
הפלט האחרון True מראה שהניסיון לקרוא עוד מספר לא שינה את המיקום. בבדיקת ה־pool נרשום את מספר ה־Rent ואת מספר ה־Return באובייקט בדיקה ונשווה ביניהם אחרי כל תרחיש, לרבות חריגה. אין להחזיר את המערך מתוך catch וגם מתוך finally, מפני שזה יוצר החזרה כפולה.
הפתרון עם העתקה מחזיר מערך חדש שמכיל רק את הטווח התקף. הפתרון עם lease מחייב את התוצאה להיות IDisposable, להחזיק את המערך עד השחרור ולא לאפשר שימוש אחריו. גם אז תצוגה שכבר נמסרה לצרכן יכולה לברוח, ולכן חוזה ה־API צריך להבהיר את תחום החיים של כל השאלה או להגביל את הגישה לפונקציה סינכרונית.