לדלג לתוכן

פתרון גנריקה וחוזי תוצאה

האלגוריתם מחזיר את האיבר הראשון במקרה של שוויון. הפרמטר out מאותחל גם כשהטווח ריק, ולכן הצרכן חייב לבדוק את הערך הבוליאני לפני שימוש בתוצאה.

var input = new Packet[] { new(3), new(9), new(9) };
Console.WriteLine(TryMax<Packet>(input, out var result));
Console.WriteLine(result.Cost);

static bool TryMax<T>(ReadOnlySpan<T> values, out T result)
    where T : struct, ICost
{
    result = default;
    if (values.IsEmpty) return false;
    result = values[0];
    for (int i = 1; i < values.Length; i++)
        if (values[i].Cost > result.Cost) result = values[i];
    return true;
}
interface ICost { int Cost { get; } }
readonly record struct Packet(int Cost) : ICost;

המפעל הבא מעתיק את הקלט ואינו מוציא החוצה מערך שניתן לשנות דרך ה־API הרגיל שלו. זוהי שכבת API לתוכן מהימן, ולא גבול אבטחה מול reflection או קוד unsafe שמכוון לעקוף אותה.

sealed class Snapshot
{
    private readonly byte[] data;
    public Snapshot(ReadOnlySpan<byte> source) => data = source.ToArray();
    public int Length => data.Length;
    public byte this[int index] => data[index];
    public void CopyTo(Span<byte> target) => data.CopyTo(target);
}

החזרת ReadOnlyMemory לבדה מגבילה את הפעולות הזמינות דרך אותה תצוגה, אבל אינה מבטלת aliases שנוצרו קודם. העתקת הקלט היא זו שניתקה את הבעלות מן המערך של הקורא. השונות חלה על המרת references תואמת; רצף int דורש פעולה מפורשת כמו Select שמבצעת boxing לכל ערך. ניתוח nullable יעזור לחייב בדיקת null בממשק שמחזיר PacketClass?, אך אינו יכול להחליף בדיקה בוליאנית של TryMax שמחזיר מבנה.