?
Was du da ansprichst ist eine Design-Sache mit den Collections in .Net, nicht mit C#. Man hat die Collections so gemacht, weil es Sprachen gibt, die keine unsigned-Datentypen kennen und mit diesen soll man die Collections-Lib auch benutzen können. Generell finde ich unsigned-Typen nicht so wahnsinnig wichtig und auch nicht, dass man mit ihnen indiziert. Warum genau stört dich das jetzt so krass?
zu 1)
Readonly Wrapper ist für mich ein neuer Begriff, aber ich kann mir vorstellen, dass man damit schon was anfangen kann. Das ist sicherlich eine Möglichkeit. Wenn ich aber jemanden für eine Funktion eine Eingabe mitgeben will dann würde ich schon gerne verhindern, dass der Wert verändert wird.
Wie gesagt, da muss man für den Einzelfall Lösungen suchen.
const in C++ lässt einen Typen sich je nach Kontext unterschiedlich verhalten. Einen solchen Mechanismus gibt es in C# nicht, stattdessen spezifiziert man über den Typ, welche Operationen möglich sein sollen.
Wenn du beispielsweise ein Array von Tieren an eine Funktion übergeben sollst, die nur die Tiere auf der Kommandozeile ausgibt, dann ist schon was schiefgelaufen. Der Funktion würde es völlig reichen, ein IEnumerable<Tier> zu erhalten und mehr Anforderungen sollte sie an den Parameter auch nicht stellen. Man sollte immer nur die Mindestanforderung an den Parameter spezifizieren. Mit nem Array spezifizierst du random write-access, weil dieser Typ diese Funktionalität eben bereitstellt. Wenn du nicht willst, dass sie zur Verfügung steht oder nötig ist, dann gibst du das Array als was allgemeineres weiter, zum Beispiel als IList<Tier> oder IEnumerable<Tier> (beides wird von Tier[] implementiert).
Also Fazit: Die Typisierung in der Schnittstelle entscheidet, welche Operationen möglich sind. Dementsprechend musst du den richtigen Typ aussuchen. Dabei musst du nicht notwendigerweise dein Objekt erst wrappen, zum Beispiel implementiert ein Array schon IEnumerable<T> und IList<T>.