Archiv des Tags ‘csharp’

C#2008 Sprachfeatures Teil 2: Automatische Properties

Freitag, den 25. Januar 2008

Ihr kennt sicherlich das mühsame Erstellen und Tippen von Properties für reine Datenhaltungsklassen. Will man unter C#2005 ein Property in einer Klasse modellieren, so muss man eine private Membervariable und ein zugehöriges Property mit Getter und Setter implementieren. Dies sieht dann in etwas so aus:

   private string _myProperty;

   public string MyProperty {
      get { return this._myProperty; }
      set { this._myProperty = value; }
   }

Man kann sich vorstellen, dass dieser Prozess bei Klassen mit mehreren Properties sehr umständlich ist! In C#2008 gibt es jetzt aber automatische Properties. Das obige Codesegment kann in C#2008 folgendermassen ausgedrückt werden:

   public string MyProperty { get; set; }

Wie man dem obigen Codeausschnitt entnehmen kann, muss man nur den Accesmodifier, den darunterliegenden Datentyp, den Propertynamen und einen leeren Get und Set Teil erstellen. Zur Kompilierzeit wird dem Property ein privates Feld und eine dazugehörige Implementation hinzugefügt (dies alles unter der Haube).

Einschränkungen
Es ist nicht möglich read-only oder write-only Properties zu definieren. Also folgende Codesegmente sind nicht erlaubt:

   public string MyProperty { get; }

oder

   public string MyProperty { set; }

Ebenfalls ist es nicht möglich in einer Klasse die ein automatisches Property deklariert auf die darunterliegende private Membervariable zu zugreifen, da das Feld ja erst zur Kompilierzeit quasi “induziert” wird. Die Klasse selber muss also immer die Propertysyntax brauchen. Z.B.

class MyExampleClass{
   public string MyProperty { get; }

   public override string ToString() {
      return string.Format("Tracelight.ch rocks! {0}", MyProperty);
   }
}

Eine weitere Einschränkung liegt darin, dass die automatischen Properties immer den Defaultwert des darunterliegenden Datentypes haben und nicht auf einen anderen Defaultwert initialisiert werden können. D.h. Referenzen sind immer null während z.B. Integer den Wert 0 haben usw. Will man den Properties beim Erstellen der Klasse einen Wert zuweisen, so muss dies über den Konstruktor der Klasse geschehen. Folgendes Beispiel demonstriert dies:

class MyClass {
   public string MyProperty { set; get; }

   public MyClass(string mypropValue) {
      MyProperty = mypropValue;
   }
}

Zugriff einschränken
Es ist möglich auch bei automatischen Properties dem Getter und Setter unterschiedliche Accessmodifier zu geben. Folgendes Codesegment sei gegeben:

   private string _myprop;

   public string MyProperty {
      get { return _myprop; }
      protected set { _myprop = value; }
   }

Dies kann unter C#2008 folgendermassen dargestellt werden:

   public string MyProperty { get; protected set; }

Somit ist es also nur aus ableitenden Klassen das Property MyProperty zu setzen.

Viel Spass

Richtiges Invoke von UI Controls

Samstag, den 19. Januar 2008

Zu diesem Thema gibt es meiner Meinung nach im Netz nicht viel schlaue Links und Hinweise, da wollte ich mal ein bisschen aufräumen. Aber zuerst einmal um was es da genau geht.

Wenn man mit dem Visual Studio ein GUI erstellt und auf diesem GUI zum Beispiel eine Textbox hinzufügt , diese GUI dann kompiliert und ausführt, dann laufen alle GUI Operationen im sogenannten Main- oder auch UI-Thread. Dieser Thread ist zuständig für das richtige Updaten, Zeichen etc. der Benutzerelemente.

Programmiert man eine Funktion die viel Rechenzeit braucht und führt diese Funktionen in einem neuen Thread aus, so muss man die Crossthreadingcalls beachten, wenn man aus dem neu erstellten Thread auf die Benutzerelemente des Mainthreads zugreifen will (um zum Beispiel in der Textbox einen Text hinzuzufügen). Denn greift man ohne zusätzliche Sicherheit einfach aus dem zweiten Thread auf das Text Property der Textbox zu, so kann aus unter Umständen dazu führen, dass zwei Thread s zur gleichen Zeit auf die Textbox zugreifen und es kommt zu unvorhersagbaren Verhalten auf dem GUI. Doch wie kann man dies umgehen?

Die Lösung heisst Delegates und Control.Invoke().

Nehmen wir an wir haben eine Methode MyMethod du jedesmal wenn Sie von einem anderen Thread aufgerufen wird auf dem GUI den Text eines Labels myControl auf “Vom Thread aufgeweckt!” setzt. Damit die Methode MyMethod threadsafe aufgerufen werden kann, muss folgendes Codesegment implementiert werden:

Methode ohne Parameter und zugehöriges Delegate

Private delegate void MyMethodDelegate();
Private void MyMethod() {
	if(myControl.InvokeRequired) {
		myControl.Invoke(new MyMethodDelegate(MyMethod));
		return;
	}
	// Add rest of the code here
        myControl.Text = "Vom Thread aufgeweckt!";
}

Der Ablauf des obigen Codesegments ist folgendermassen. Man definiert ein Delegate (quasi typensicherer Methodenpointer), das später auf die Methode MyMethod “zeigt”. Danach prüft man in der eigentlichen Methode über myControl.InvokeRequired ob das Control aus einem anderen Thread angesprochen wurde. Ist dies der Fall, so führt man ein Invoke auf myControl über myControl.Invoke mit dem Delegate MyMethodDelegate durch und übergibt dem Delegate die aufgerufene Methode (hier MyMethod) als Parameter. Nach dem Invoke verlässt man die Methode direkt wieder über die Anweisung return;. Der eigentliche Zugriff auf das Control myControl erfolgt dann im Codeblock // Add rest of the code here.

Die Logik dahinter ist, dass durch den Aufruf von Inkvoke auf das Control, wird über das Delegate die Methode nach einmal aufgerufen und der zugreifende Thread meldet sich quasi beim UI-Thread an und wartet, bis dieser den Zugriff auf das Control frei gibt. Sobald dies der Fall ist, kann der Thread in die Methode und dieses Mal ist das Flag InvokeRequired auf false gesetzt und es wird nur der eigentliche Codeblock bei // Add rest of the code here ausgeführt.

Doch wie funktioniert das Ganze, wenn die Methode MyMethod ein oder mehrere Parameter entgegen nimmt? Hier ist der Codeauszug:

Methode mit Parameter und zugehöriges Delegate

Private delegate void MyMethodWithParameterDelegate(string message);
Private void MyMethodWithParameter(string myParameter) {
	if(myControl.InvokeRequired) {
		myControl.Invoke(new
MyMethodWithParameterDelegate(MyMethodWithParameter), new object[]{ myParameter });
		return;
	}
	// Add rest of the code here
        myControl.Text = myParameter;
}

Der Ablauf ist wieder genau gleich, einfach wird in diesem Fall ein Delegate mit Parameter spezifiziert und beim Invoke wieder ein Delegate erstellt und die Parameter für die Methode als Objektarray übergeben. That’s it!

Viel Spass beim Ausprobieren…

Nullable Types in C#

Donnerstag, den 13. Dezember 2007

Heute möchte ich kurz auf die Nullable Types in C# eingehen. Dabei sollen folgende Fragen geklärt werden:

  • Was sind Nullable Types?
  • Wozu braucht es Nullable Types

Allgemein sollte bekannt sein, dass in C# Referenzen auf Objekte auf null gesetzt werden können. Bei primitiven Datentypen wie int, float etc. ist dies aber nicht möglich. Folgende Codesequenz würde als in C# zu einem Kompilerfehler führen:


int zahl = null;

Der meist-gesehene Ansatz um die primitiven Datentypen zu initialisieren, war lange Zeit, dass man z.B. einfach die Integer mit “-1″ vorgeladen hat. Dieser Ansatz ist aber nicht wirklich elegant und musste jeweils entsprechend dokumentiert werden. Nun kommen die Nullable Types ins Spiel. Nullable Types werden in C# mit einen “?” nachgestellt dem primitiven Datentyp gekennzeichnet. Der obige Code würde also folgendermassen aussehen:


int? zahl = null;

Nullable Types haben zwei wichtige Properties die nun ins Spiel kommen. Zum einen ist dies das Property Value, das den Wert des Types beinhaltet und zum andern das Property HasValue das True oder False liefert, falls Value gesetzt ist oder nicht. Das Property Value wird automatisch angesprochen wenn man ein Code wie den untenstehenden schreibt:


int result = zahl + 42;

Ist aber zahl == null, so gibt das obige Codebeispiel eine Runtimeexception. Jetzt kann der Entwickler einfach folgende Codezeile schreiben:


if(zahl.HasValue) {
int result = zahl + 42;
}

Elegant ist auch, dass man die Möglichkeit hat einen Defaultwert bei Nullable Types zurückzugeben, falls der Nullable Type null ist. Die funktioniert folgendermassen:


int? zahl1 = null;
int zahl2 = zahl1 ?? 42;

Der obige Code zeigt in der zweiten Zeile wie ein Defaultwert gesetzt werden kann. Falls zahl1 == null wird zahl2 mit 42 initialisiert!

Mehr zu Nullable Types: