1. Herfried K. Wagner’s VB.Any
  2. .NET
  3. Artikel

Behandlung ungültiger konstanter Angaben für Arraygrößen, -grenzen und -indizes in Visual Basic .NET und C#

Einleitung

Oft wird bei Diskussionen zwischen Benutzern der Programmiersprachen Visual Basic .NET und C# von Seiten der C#-Benutzer vorgebracht, daß in C# geschriebener Quellcode expliziter sei als in Visual Basic .NET mit aktiviertem Option Strict On abgefaßter Code. Einer näheren Betrachtung hält diese Aussage jedoch nicht stand. Der vorliegende Artikel demonstriert, ausgehend von einer Diskussion in Microsofts öffentlichen Newsgroups, am Beispiel der Behandlung ungültiger konstanter Angaben für Arraygrößen, -grenzen und -indizes mangelnde Explizitheit in der Programmiersprache C# und eine in diesem Zusammenhang auftretende unbedeutende Inkonsistenz im Verhalten des Compilers der Programmiersprache Visual Basic .NET.

Der besseren Lesbarkeit halber werden im Folgenden anstelle der sprachspezifischen Typpseudonyme Integer/int und Long/long die Typnamen System.Int32 und System.Int64 aus der Klassenbibliothek des .NET Framework verwendet. Die Dokumentation zu den im vorliegenden Text genannten Fehlernummern des Visual Basic .NET-Compilers kann man sich mit Hilfe des Werkzeugs BcHelp von Mattias Sjögren anzeigen lassen.

Größen von Arraydimensionen in .NET

In .NET ist die Anzahl der Elemente in einem Array durch die größte im Typ native int, also etwa int32 (System.Int32), darstellbare Zahl begrenzt ([1], Teil III „CIL Instruction Set“, Kap. 4.19 „newarr – create a zero-based, one-dimensional array“, S. 113). Die Programmiersprachen Visual Basic .NET und C# unterstützen Elementanzahlen des Typs Int32 je Dimension. Damit wird die Anzahl von Elementen einer Dimension durch den prozessorunabhängigen Wert von Int32.MaxValue nach oben begrenzt. Der als Arraygröße, -grenze und -index angegebene Wert muß schlußendlich in Form des Typs Int32 vorliegen. Visual Basic .NET und C# unterscheiden sich darin, wie sichergestellt wird, daß konstante Angaben bei den jeweiligen Sprachelementen im gültigen Wertebereich zu liegen kommen.

Das Verhalten von Visual Basic .NET

In den Anweisungen Dim und ReDim sowie bei Arrayzugriffen übergebene Grenzen und Indizes müssen den Typ Int32 besitzen ([2], Kap. 9.6.3.3 „Array-Size Initializers). Werden sie in Form eines anderen ganzzahligen Datentyps übergeben, ist eine Typumwandlung zu Int32 mittels CInt oder CType erforderlich; andernfalls tritt ein beim Versuch, den Code zu kompilieren, der Kompilierungsfehler BC30439 („Option Strict On läßt keine impliziten Typumwandlungen von Long in Integer zu“) auf. Betrachten wir dazu das im nachstehenden Listing angegebene Beispiel der Dim-Anweisung.


' Erstellen eines Arrays mit 'Int32.MaxValue' + 100 Elementen.
Dim n As Int64 = Int32.MaxValue + 99L
Dim Data(n) As Byte

Versucht man, eine negative Elementanzahl ungleich −1 (dieser Anzahl kann übergeben werden, um das Array zu leeren) des Typs Int32 zu übergeben, löst der Compiler den Fehler BC30611 („Arraydimensionen können keine negative Größe haben“) aus. Lediglich im Fall der Übergabe des unzulässigen Werts von Int32.MaxValue wird zur Laufzeit eine Ausnahme des Typs System.OverflowException („Die arithmetische Operation hat einen Überlauf verursacht“) geworfen.

Das Verhalten von C#

Verglichen mit Visual Basic .NET stellt C# wesentlich geringere Anforderungen an konstante Angaben für Arraygrößen und -indizes. Die Spezifikation fordert lediglich, daß die übergebene Größe bzw. der Index implizit in den Typ Int32 umwandelbar ist ([3], Kap. 19.3 „Array element access“, S. 276). Falls eine Typumwandlung erforderlich wird, die Angabe also nicht den Typ Int32 besitzt, erfolgt diese zur Laufzeit. Nachstehendes Listing enthält zum im vorigen Listing angegebenen Visual Basic .NET-Code äquivalenten Code in C#.


// Erstellen eines Arrays mit 'Int32.MaxValue' + 100 Elementen.
Int64 n = Int32.MaxValue + 100L;
byte[] Data = new byte[n];

Der oben angegebene Code läßt sich fehlerfrei kompilieren. Bei der Ausführung wird jedoch eine Ausnahme des Typs System.OverflowException („Die arithmetische Operation hat einen Überlauf verursacht“) geworfen, da 2.147.483.648 nicht im Datentyp Int32 dargestellt werden kann. Der Compiler erkennt ungültige konstante negative Angaben für Größen und Indizes und behandelt sie mit der Kompilierungswarnung (Stufe 2) CS0251 („Indizierung eines Arrays mit einem negativen Index (Arrayindizes starten immer mit Null)“). Über die Compileroption /warnaserror des Befehlszeilencompilers csc.exe kann die Warnung wie ein Fehler gehandhabt werden; eine entsprechende Option besteht auch in den Projekteigenschaften von C#-Projekten innerhalb der Entwicklungsumgebung Visual Studio .NET.

Schlußwort

Wie anhand von Beispielen gezeigt wurde, unterscheiden sich Visual Basic .NET und C# bei der Handhabung konstanter Angaben für Arraygrößen, -grenzen und -indizes, sofern diese nicht den Typ Int32 besitzen. Visual Basic .NET prüft konstante Angaben bis auf einen Ausnahmefall zur Kompilierungszeit auf deren Gültigkeit und schöpft damit die Möglichkeiten eines Compilers in hohem Maße aus. Im Gegensatz dazu stellt C# Validierung dieser Angaben zur Kompilierungszeit in weit geringerem Umfang bereit. Während durch eine Anpassung des Compiler von Visual Basic .NET bestehender Code nur in geringem Ausmaß verändert werden müßte, würde eine Änderung im Verhalten des C#-Compilers umfangreichere Nachbearbeitungen des Codes erforderlich machen. Daher ist es unwahrscheinlich, daß das spezifizierte Verhalten des Compilers von C# in einer zukünftigen Version zu Gunsten einer umfassenderen Überprüfung des Quellcodes auf semantische Korrektheit zur Kompilierungszeit verändert wird.

Literaturverzeichnis

[1]
Microsoft Corporation: Standard ECMA-335 – Common Language Infrastructure (CLI), 2nd edition, ECMA, Dezember 2002.
[2]
Microsoft Corporation: Visual Basic Language Specification, Dokumentation zu Visual Basic .NET 2003, MSDN, 2003.
[3]
Microsoft Corporation: Standard ECMA-334 – C# Language Specification, 2nd edition, ECMA, Dezember 2002.