Glengamoi (Forum) · AspHeute · .NET Heute (RSS-Suche) · AspxFiles (Wiki) · .NET Blogs

Arrays mit Index und Schlüssel

Geschrieben von: Christoph Wille
Kategorie: C#

This printed page brought to you by AlphaSierraPapa

Arrays sind ein tolle Erfindung - man greift per Index bequem auf die Elemente zu. Will man nicht per Index auf ein Element zugreifen sondern per Schlüssel, dann verwendet man die Hashtable Klasse. Doch was wenn man sowohl per Index als auch Schlüssel auf Elemente zugreifen will? Auch dann wird man von .NET nicht alleine gelassen, denn es gibt die SortedList Klasse, eine Mischung aus Array und Hashtable.

1,2,3 - so einfach geht's!

Die SortedList ist also eine Mischung aus Array und Hashtable. Daß die Verwendung dadurch nicht komplizierter wird, demonstriert gleich das erste Beispiel (access.aspx):

<% @Page Language="C#" %>
<% @Import Namespace="System.Collections" %>
<%
SortedList slDotNetLists = new SortedList();
slDotNetLists.Add("ASP.NET", "aspDEdotnet@aspfriends.com");
slDotNetLists.Add("C#", "dotnetDEcsharp@aspfriends.com");
slDotNetLists.Add("VB.NET", "dotnetDEvb@aspfriends.com");

Response.Write(slDotNetLists.GetByIndex(0).ToString() + "<br>");
Response.Write(slDotNetLists["C#"].ToString() + "<br>");
int nIndex = slDotNetLists.IndexOfKey("VB.NET");
Response.Write(slDotNetLists.GetByIndex(nIndex).ToString() + "<br>");
%>

Das Hinzufügen von Elementen funktioniert schon wie bei der Hashtable Klasse gelernt. Die Zugriffe auf die Elemente sind der interessante Part, zuerst per Index:

object objValue = slDotNetLists.GetByIndex(0);

Der Zugriff auf ein Element passiert via GetByIndex Methode. Warum nicht per Indexer, also den eckigen Klammern? Nun, die sind für den Zugriff via Schlüssel reserviert:

object objValue = slDotNetLists["C#"];

Um zu zeigen daß man auch mit der Kirche um's Kreuz zum Ziel kommen kann, habe ich noch folgende Zugriffsvariante eingebaut:

int nIndex = slDotNetLists.IndexOfKey("VB.NET");
object objValue = slDotNetLists.GetByIndex(nIndex);

Man kann den Indexwert eines Schlüssel ermitteln, und dann per GetByIndex an den Wert kommen.

Die korrekte Verwendung von foreach

Was soll man da eigentlich falsch machen können, werden sich einige fragen. Sehen wir uns einmal die Standardanwendung an (iterateforeach.aspx):

<% @Page Language="C#" %>
<% @Import Namespace="System.Collections" %>
<%
SortedList slDotNetLists = new SortedList();
slDotNetLists.Add("ASP.NET", "aspDEdotnet@aspfriends.com");
slDotNetLists.Add("C#", "dotnetDEcsharp@aspfriends.com");
slDotNetLists.Add("VB.NET", "dotnetDEvb@aspfriends.com");

foreach (DictionaryEntry de in slDotNetLists)
{
  Response.Write(de.Key + " - " + de.Value + "<br>\r\n");
}
%>

Prinzipiell ist das in ASP.NET auch so OK, nur: der Enumerator ist nicht thread-safe. Was bedeutet das? Angenommen, ich habe eine größere Anwendung, in der ein Teil des Programms die SortedList ändert (Einträge hinzufügt oder löscht), und ein anderer die Daten listet. Was passiert, wenn während des Auflistens ein Wert herausgelöscht wird? Nun, das foreach wird möglicherweise mit einer Exception "sterben", weil ich ohne "Wissen" des Enumerators ein Element herausgelöscht habe, auf das er möglicherweise zugreifen wird.

Um dies zu verhindern, kann man die SortedList synchronisieren, das heißt sich eine thread-sichere Kopie geben lassen. Daß dies keineswegs ein grober Mehraufwand ist demonstriert iteratesynchronized.aspx:

<% @Page Language="C#" %>
<% @Import Namespace="System.Collections" %>
<%
SortedList slDotNetLists = new SortedList();
slDotNetLists.Add("ASP.NET", "aspDEdotnet@aspfriends.com");
slDotNetLists.Add("C#", "dotnetDEcsharp@aspfriends.com");
slDotNetLists.Add("VB.NET", "dotnetDEvb@aspfriends.com");

SortedList slSynchronized = SortedList.Synchronized(slDotNetLists);
Response.Write(slSynchronized.IsSynchronized.ToString() + "<br>");

foreach (DictionaryEntry de in slSynchronized)
{
  Response.Write(de.Key + " - " + de.Value + "<br>\r\n");
}
%>

Nur der Aufruf der statischen Methode Synchronized ist notwendig, um thread-sicher mit foreach arbeiten zu können. Die Abfrage von IsSynchronized dient eigentlich nur der Demonstration daß man leicht herausfinden kann, ob man mit einer synchronisierten SortedList arbeitet oder nicht.

Suchen in der SortedList

Oftmals möchte man sich versichern, daß bestimmte Einträge auch wirklich in der SortedList sind. Dann wird man die auch schon von der Hashtable Klasse bekannten Methoden ContainsKey und ContainsValue verwenden. Das folgende Beispiel (search.aspx) ist nichts weiter als eine leicht angepasste Version des Scripts, das ich auch schon für die Hashtable Klasse verwendet habe.

<% @Page Language="C#" %>
<% @Import Namespace="System.Collections" %>
<%
SortedList slDotNetLists = new SortedList();
slDotNetLists.Add("ASP.NET", "aspDEdotnet@aspfriends.com");
slDotNetLists.Add("C#", "dotnetDEcsharp@aspfriends.com");
slDotNetLists.Add("VB.NET", "dotnetDEvb@aspfriends.com");

// Anzahl der Element in der SortedList
int nElementCount = slDotNetLists.Count;

// existiert der Schlüssel?
bool bKeyCont = slDotNetLists.ContainsKey("C#");

// existiert der Wert?
bool bValueCont = slDotNetLists.ContainsValue("dotnetDEvb@aspfriends.com");

// Element korrekt suchen
if (true == bKeyCont)
{
  Response.Write(slDotNetLists["C#"].ToString());
}
%>

Updaten und Löschen

Üblicherweise befüllt man eine Collection nicht nur, sondern man möchte auch Werte ändern und sogar löschen können. Das kann die SortedList Klasse natürlich auch - wie im folgenden Beispiel gezeigt (updateremove.aspx):

<% @Page Language="C#" %>
<% @Import Namespace="System.Collections" %>
<%
SortedList slDotNetLists = new SortedList();
slDotNetLists.Add("ASP.NET", "aspDEdotnet@aspfriends.com");
slDotNetLists.Add("C#", "dotnetDEcsharp@aspfriends.com");
slDotNetLists.Add("VB.NET", "dotnetDEvb@aspfriends.com");

// existiert der Schlüssel?
bool bKeyCont = slDotNetLists.ContainsKey("VB.NET");

// Element korrekt updaten
if (true == bKeyCont)
{
  slDotNetLists["VB.NET"] = "deadinthewater@nowhere.org";
}

// Element löschen; existiert es nicht --> Exception
slDotNetLists.Remove("VB.NET");

// und jetzt löschen wir alles
slDotNetLists.Clear();
%>

Die Methode ContainsKey ist bereits ein alter Bekannter, ebenso wie der Indexer - nur daß ich ihn hier zum Ändern des Wertes verwende. Ebenso einfach ist die Verwendung der Remove Methode, die ein einzelnes Element anhand des Schlüssels aus der SortedList entfernt. Last but not least bleibt mir die Clear Methode zu erklären: diese löscht sämtliche Elemente aus der SortedList.

Schlußbemerkung

Die SortedList Klasse ist ein weiterer Beweis dafür, daß man im Framework für fast jeden Bedarf eine bereits existierende Klasse finden kann.

This printed page brought to you by AlphaSierraPapa

Download des Codes

Klicken Sie hier, um den Download zu starten.
http://www.aspheute.com/code/20020124.zip

Verwandte Artikel

Collections einmal anders: Stacks und Queues
http:/www.aspheute.com/artikel/20000926.htm
Das foreach Statement
http:/www.aspheute.com/artikel/20000720.htm
Debugging in der Tiefe
http:/www.aspheute.com/artikel/20020401.htm
Die Hashtable Klasse
http:/www.aspheute.com/artikel/20000823.htm
Sortieren mit dem IComparer Interface
http:/www.aspheute.com/artikel/20020417.htm
Verwendung von Arrays in C#
http:/www.aspheute.com/artikel/20000731.htm

 

©2000-2006 AspHeute.com
Alle Rechte vorbehalten. Der Inhalt dieser Seiten ist urheberrechtlich geschützt.
Eine Übernahme von Texten (auch nur auszugsweise) oder Graphiken bedarf unserer schriftlichen Zustimmung.