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

Liste

.NET 2.0 (1)
.NET Allgemein (16)
.NET Fu (5)
ADO.NET (11)
Aprilscherz (3)
ASP Grundlagen (44)
ASP Tricks (83)
ASP.NET (44)
ASPIntranet.de (5)
C# (28)
Datenbank (44)
Dokumentation (4)
IIS 6.0 (1)
Komponenten (29)
Optimierung (10)
Server (21)
Sicherheit (34)
Tee Off (6)
VB.NET (6)
WAP (8)
Web Services (11)
XML (9)

RSS 2.0 - Die neuesten fünf Artikel auf AspHeute.com


 

Suchen





 

English Articles
Chinese Articles
Unsere Autoren
 
Link zu AspHeute
Impressum
Werben
Anfragen

Unions in C#

Geschrieben von: Christoph Wille
Kategorie: C#

Wer aus der C/C++ Welt kommt, kennt die Unions und ihr Funktionsprinzip bereits: diese erlauben es, an einer Speicheradresse unterschiedliche Datentypen zu speichern. Mit erstaunlich geringem Aufwand lassen sich Unions auch in C# nachbilden, und zwar mit Hilfe der Attribute StructLayout und FieldOffset.

Die beiden erwähnten Attribute dienen im Normalfall dafür, daß das Speicherlayout einer gewissen Struktur vordefiniert wird, und nicht von der CLR nach ihrem Gutdünken optimiert wird. Dieses automatische Layout muß besonders bei Struct's verhindert werden, die per PInvoke an Betriebssystemfunktionen übergeben werden - und für diesen Zweck wurden die Attribute eingeführt.

Dadurch, daß man das Speicherlayout genau definieren kann, eröffnet sich aber auch die Möglichkeit, eine Variable über andere "drüberzulegen". Damit das nicht zu theoretisch ist, hier eine Beispiel-Union:

[StructLayout(LayoutKind.Explicit)] 
public struct SampleUnion
{
  [FieldOffset(0)] public bool Flag1;
  [FieldOffset(1)] public bool Flag2;
  [FieldOffset(2)] public bool Flag3;
  [FieldOffset(3)] public bool Flag4;
  [FieldOffset(0)] public long Composite;
}

Die Struct hat fünf Members, vier davon sind boolsche Werte, der fünfte ist vom Datentyp long. Unter normalen Umständen würde die Struct gesamt 4 mal 1 Byte plus 1 mal 4 Byte also 8 Byte Speicher verbrauchen - nur diese Struct ist anders. Die Änderung kommt durch die Verwendung von FieldOffset ins Spiel: damit kann ich sagen, an welcher Byteposition der jeweilige Member positioniert werden soll (StructLayout garantiert mein Layout). Und was habe ich gemacht? Nun, Composite beginnt am Anfang der Struct, und wird von allen vier boolschen Members überlappt. Somit ist die Struct 4 Byte groß.

Das bedeutet nun in deutschen Worten folgendes: verändere ich einen der boolschen Members, ändert sich der Wert von Composite. Ändere ich hingegen Composite, ändern sich die boolschen Members, die bitmäßig im Bereich der Änderungen liegen (also nicht notwendigerweise immer alle). Ansehen kann man sich das Verhalten mit folgendem Sample:

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Explicit)] 
public struct SampleUnion
{
  [FieldOffset(0)] public bool Flag1;
  [FieldOffset(1)] public bool Flag2;
  [FieldOffset(2)] public bool Flag3;
  [FieldOffset(3)] public bool Flag4;
  [FieldOffset(0)] public long Composite;
}  

class Sample
{
public static void Main()
{
  SampleUnion su = new SampleUnion();
  su.Flag1 = false;
  Console.WriteLine(su.Composite.ToString());
  su.Flag2 = true;
  Console.WriteLine(su.Composite.ToString());
  su.Flag3 = false;
  Console.WriteLine(su.Composite.ToString());
  su.Flag4 = true;
  Console.WriteLine(su.Composite.ToString());
}

Am Anfang ist Composite noch 0, doch der Wert ändert sich, sobald eines der Flags auf true gesetzt wird.

Jetzt haben wir zwar eine Union mit vier boolschen Flags, aber wozu kann man in dieser speziellen Struct den long-Wert einsetzen? Das folgende Beispiel (union.cs) zeigt - versteckt - eine Möglichkeit:

// using und struct-Definition zur leichteren Lesbarkeit entfernt
class Sample
{
public static void Main()
{
  SampleUnion su = new SampleUnion();
  su.Flag1 = false;
  su.Flag2 = true;
  su.Flag3 = false;
  su.Flag4 = true;
  DumpUnion(su);
  DumpUnion2(su.Composite);
}

public static void DumpUnion(SampleUnion su)
{
  Console.WriteLine("Flag1 " + su.Flag1.ToString());
  Console.WriteLine("Flag2 " + su.Flag2.ToString());
  Console.WriteLine("Flag3 " + su.Flag3.ToString());
  Console.WriteLine("Flag4 " + su.Flag4.ToString());
  Console.WriteLine("Composite " + su.Composite.ToString());
}

public static void DumpUnion2(long nUnionValue)
{
  SampleUnion su = new SampleUnion();
  su.Composite = nUnionValue;
  Console.WriteLine("Flag1 " + su.Flag1.ToString());
  Console.WriteLine("Flag2 " + su.Flag2.ToString());
  Console.WriteLine("Flag3 " + su.Flag3.ToString());
  Console.WriteLine("Flag4 " + su.Flag4.ToString());
  Console.WriteLine("Composite " + su.Composite.ToString());
}
}

Der Verwendungszweck wird in DumpUnion2 ersichtlich - ich kann meine Union als ganz simple long-Variable an Funktionen übergeben, allerdings jederzeit nach Belieben die originale Union wieder erstellen - es sind nur zwei Zeilen:

  SampleUnion su = new SampleUnion();
  su.Composite = nUnionValue;

Die Möglichkeit eine Union als andere Datentypen zu repräsentieren beginnt dann seine Vorteile zu entfalten, wenn man nur Teile einer Struct übergeben möchte, und nicht gleich alle Daten. Und mit der Möglichkeit andere Datentypen in ein und dieselbe Speicheradresse zu legen eröffnet sich eine ganze Reihe von interessanten Anwendungen. Ein Beispiel sei erwähnt: es ist einfacher und schneller einen long-Wert per SOAP zu marshalen als die Struct gesamt.

Schlußbemerkung

Der durchschnittliche Programmierer wird kaum mit Unions in Berührung kommen, es ist aber doch sehr beruhigend wenn man weiß, daß man auch unter .NET's rigiden Regiment zumindest ein wenig mit dem Speicher spielen darf.

Download des Codes

Klicken Sie hier, um den Download zu starten.

Verwandte Artikel

Datentypen in C#
Enums lesbar machen
Sichere Konvertierungen von Referenztypen
Variable Parameterlisten in Funktionen
Web Services 101 in ASP.NET

Wenn Sie jetzt Fragen haben...

Wenn Sie Fragen rund um die in diesem Artikel vorgestellte Technologie haben, dann schauen Sie einfach bei uns in den Community Foren der deutschen .NET Community vorbei. Die Teilnehmer helfen Ihnen gerne, wenn Sie sich zur im Artikel vorgestellten Technologie weiterbilden möchten.

Eine weitere sehr hilfreiche Resource ist das deutsche ASP.NET Wiki, das als zentrale Anlaufstelle für Tips, Tricks, Know How und alles Nützliche was man in seinem Alltag als (ASP).NET-Entwickler so braucht und entdeckt gedacht ist.

Haben Sie Fragen die sich direkt auf den Inhalt des Artikels beziehen, dann schreiben Sie dem Autor! Unsere Autoren freuen sich über Feedback zu ihren Artikeln. Ein einfacher Klick auf die Autor kontaktieren Schaltfläche (weiter unten) und schon haben Sie ein für diesen Artikel personalisiertes Anfrageformular.

 

Und zu guter Letzt möchten wir Sie bitten, den Artikel zu bewerten. Damit helfen Sie uns, die Qualität der Artikel zu verbessern - und anderen Lesern bei der Auswahl der Artikel, die sie lesen sollten.

Bewerten Sie diesen Artikel
 Sehr gut   Nicht genügend  
   1  2  3  4  5  
 

  
   Für Ausdruck optimierte Seite

©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.