Arbeiten mit .NET: OOP/ Einzelheiten/ Klassen und Objekte/ Modifizierer
Modifizierer, oder auch Modifikatoren, geben uns die Möglichkeit, ganz einfach zu steuern, wer wann auf welche Weise auf unsere Klassen, Eigenschaften, Ereignisse, Felder und Methoden zugreifen darf. Dabei unterscheiden wir allgemeine Modifizierer und sogenannte Zugriffsmodifizierer als eigene Gruppe innerhalb der Modifizierer.
Dieser Abschnitt beschäftigt sich mit den speziellen Modifizierern. Den ersten Überblick der wichtigsten Modifizierer haben wir uns im Abschnitt Die wichtigsten Modifizierer bereits angesehen.
Zugriffsmodifizierer
[Bearbeiten]Protected
[Bearbeiten]Da public den Zugriff stets vollständig ein- und private stets vollständig abschaltet, muss es noch etwas geben, das uns die Vererbung ermöglicht, ohne dass gleich jeder auf unsere Typmitglieder zugreifen kann. Dazu gibt es den Zugriffsmodifizierer protected. So geschützte Klassen und deren Mitglieder können ausschließlich von den Erben genutzt werden. Andere haben darauf keinen Zugriff.
protected class Zugriffstest_Protected { // ... ein geschütztes Feld protected string m_Protected_Feld = "Geschütztes Feld"; // ... eine geschützte Eigenschaft protected string Protected_Eigenschaft { get { return "Geschützte Eigenschaft"; } set { m_Protected_Feld = value; } } // ... ein geschütztes Ereignis protected delegate void Protected_Delegate(); protected event Protected_Delegate Protected_Ereignis; // ... eine geschützte Methode protected string Protected_Methode() { return "Geschützte Methode"; } }
Siehe auch: MSDN C# Referenz (protected)
Internal
[Bearbeiten]Stellen wir uns vor, wir würden eine Komponente programmieren, die mehrere Klassen benutzt. Diese Klassen wiederum müssen sich einige ihrer Mitglieder teilen; beispielsweise ruft eine Klasse Methoden der anderen auf. Allerdings möchten wir gern verhindern, dass später, also wenn die Komponente verwendet wird, jemand diese Methoden aufrufen kann. Zu diesem Zweck gibt es den Zugriffsmodifizierer internal. So gekennzeichnete Typen und Typmitglieder sind nur innerhalb einer Assembly erreichbar:
internal class Zugriffstest_Internal { // ... ein geschütztes Feld internal string m_Protected_Feld = "Internes Feld"; // ... eine geschützte Eigenschaft internal string Protected_Eigenschaft { get { return "Interne Eigenschaft"; } set { m_Protected_Feld = value; } } // ... ein geschütztes Ereignis internal delegate void Protected_Delegate(); internal event Protected_Ereignis; // ... eine geschützte Methode internal string Interne_Methode() { return "Interne Methode"; } }
Siehe auch: MSDN C# Referenz (internal)
Protected Internal
[Bearbeiten]Mit der Kombination von protected und internal können wir noch eine weitere, ganz besonders für die Entwicklung von Komponenten und Bibliotheken interessante, Variante des Zugriffs ermöglichen. So geschützte Klassen und deren Mitglieder können nur von ihren eigenen Erben oder von anderen Klassen, die sich im gleichen Assembly befinden, erreicht werden:
protected internal class Zugriffstest_Internal { // ... ein geschütztes Feld protected internal string m_Protected_Feld = "Internes Feld"; // ... eine geschützte Eigenschaft protected internal string Protected_Eigenschaft { get { return "Interne Eigenschaft"; } set { m_Protected_Feld = value; } } // ... ein geschütztes Ereignis protected internal delegate void Protected_Delegate(); protected internal event Protected_Ereignis; // ... eine geschützte Methode protected internal string Interne_Methode() { return "Interne Methode"; } }
Dieser Fall dürfte uns aber, zumindest in der nächsten Zeit, keine Kopfschmerzen bereiten. Erst wenn wir uns anschauen, wie man Bibliotheken und Komponenten entwickelt, wird es Zeit, sich damit auseinander zu setzen.
Modifizierer
[Bearbeiten]Event
[Bearbeiten]Das event-Schlüsselwort deklariert ein Ereignis.
class EventTest { // Wir deklarieren ein Ereignis. // Der Delegat ist Bestandteil // dieser Deklaration. // Warum das so ist, finden wir // im Abschnitt "Ereignisse" dieses Buches. public delegate void EventDelegate(); public event EventDelegate Event; }
Siehe auch MSDN C# Referenz (event)
Extern
[Bearbeiten]Das Schlüsselwort extern zeigt an, dass wir eine externe Methode deklarieren möchten. Dies ist häufig der Fall, wenn wir auf die WinAPI zugreifen wollen.
class ExternTest { // Wir importieren eine Methode // aus der Bibliothek "User32.dll" [DllImport("User32.dll")] extern static public int MessageBox( int h, string text, string title, int type ); // Wir kapseln die eben importierte Methode public int Unsere_MessageBox( string text, string title ) { return MessageBox( 0, text, title, 0 ); } }
Siehe auch MSDN C# Referenz (extern)
Readonly
[Bearbeiten]Der readonly-Modifizierer wird ausschließlich für Felder verwendet, um einen „Nur-Lese-Zugriff“ zu erzeugen.
class ReadOnlyTest { // ... wir erstellen eine Nur-Lese-Variable readonly public string m_NurLeseVariable = "Mich kann man nicht ändern!"; // ... wir erstellen einen Konstruktor // und ändern dort die Nur-Lese-Variable. public ReadOnlyTest() { m_NurLeseVariable = "Oh doch! Im Konstruktor!"; } }
Im Gegensatz zum Modifizierer für Konstanten – const –, das eine Konstante erzeugt, die ebenfalls nur gelesen werden kann, ist es aber möglich, einer readonly-Variablen, Werte im Konstruktor der Klasse zuzuweisen. Deshalb nennt man sie auch Laufzeitkonstanten, während mit const deklarierte „echte“ Konstanten als Kompilierzeitkonstante bezeichnet werden.
Siehe auch: MSDN C# Programmierreferenz (readonly)
Unsafe
[Bearbeiten]Den unsafe-Modifzierer verwenden wir, wenn wir sogenannten „unsicheren“ Code schreiben wollen. Das .NET-Framework befindet sich in einem „sicheren“ Kontext. Das heißt, um viele langweilige Aufgaben, wie beispielsweise das Aufräumen des Speichers, kümmern sich spezielle Dienste ganz automatisch. Wir müssen darauf keinen Gedanken verschwenden. Wenn wir aber unsafe-Code schreiben, teilen wir dem .NET mit, dass wir auf diese Features verzichten möchten. Der Preis ist allerdings, dass wir uns dann selbst darum kümmern müssen, dass nach der Arbeit wieder aufgeräumt wird, etc. Wozu sollen wir dann aber unsicheren Code schreiben? Ganz einfach: Gelegentlich werden wir auf Programme zugreifen oder diese erweitern wollen, die noch nicht in .NET geschrieben wurden. Diese Programme sind von haus aus „unsicher“. Wenn wir deren Methoden und Klassen verwenden wollen, müssen wir „unsicheren Code“ schreiben.
class UnsafeTest { // Diese Methode benutzt unsicheren Code... unsafe static void Unsafe_Verwende_WinApi() { // Hier dürfen wir unsicheren Code schreiben oder aufrufen. // Dazu gehören auch Zeiger, // die wir ansonsten im .NET nicht verwenden können. } // Diese Methode nutzt sicheren und unsicheren Code gleichzeitig static void Safe_Unsafe_Mixed_Code() { // Hier steht sicherer Code. // Um all die nebensächlichen Dinge // kümmert sich das .NET selbst. // Jetzt wollen wir ein Stück Code schreiben, // das auf unsicheren Code zugreift. unsafe { // Hier dürfen wir unsicheren Code schreiben oder aufrufen. // Dazu gehören auch Zeiger, // die wir ansonsten im .NET nicht verwenden können. } // Hier steht sicherer Code. // Um all die nebensächlichen Dinge // kümmert sich das .NET selbst. } }
Siehe auch: MSDN C# Referenz (unsafe)
Virtual
[Bearbeiten]Eigenschaften und Methoden, aber auch Indexer und Ereignisse, die mit dem Modifizierer virtual deklariert sind, können in abgeleiteten Klassen überschrieben werden. Wie man das genau macht, schauen wir uns im Abschnitt Vererbung ganz einfach noch genauer an.
class Basisklasse { // ... eine überschreibbare Methode virtual public void Virtual_Methode() { // In dieser Methode stehen Aktionen, // die von späteren Erben dieser Klasse // geändert werden dürfen. } }
Siehe auch: MSDN C# Referenz (virtual)
Volatile
[Bearbeiten]Der Modifizierer volatile ist besonders für das Multithreading interessant. Dort wird er verwendet, um anzuzeigen, dass dieses Feld von mehreren Threads gleichzeitig geändert werden kann, ohne dass die lock-Anweisung verwendet wird. Das Schlüsselwort volatile darf für ganzzahlige Typen, Enumerationstypen, Verweistypen, Zeigertypen und generische Typparameter (vorausgesetzt, es sind Verweistypen) verwendet werden.
class VolatileTest { // ... ein "volatiles" Feld volatile public int m_Ganzzahl; }
Siehe auch: MSDN C# Referenz (volatile)