BlackCoin's Corner

In diesem Blog dreht es sich zu 90 % um den Themenbereich C# .Net

Februar 2011 - Einträge

Optional and Named Parameters

Aus der Rubrik: Neues von der Basta heute meine zweite Session C# Phase 4 mit Christian Nagel

Seit C# 4.0 unterstützt unsere geliebte Entwicklungssprache, diese recht interessante Feature. In diesem Blog Post, möchte ich diese für C# Entwickler neue Möglichkeit, einmal etwas genauer betrachten.

Obwohl die optionalen Parameter ganz klar sehr nützlich sein können, so bergen Sie auch einige Gefahren die man beachten sollte , aber fangen wir erst einmal langsam an.

Optionale Parameter was ist das eigentlich?

Manche Entwickler unter euch, werden es schon z.B. aus der VB Zeit heraus kennen.

Ihr kennt das doch, Ihr schreibt eine Methode mit sagen wir mal 5 Parameter, jedoch Ihr braucht nicht immer alle Parameter. wie in diesem Beispiel

    
        public string BuildSQL(string table) { return BuildSQL(table, "*"); }     
        public string BuildSQL(string table, string columns) { return BuildSQL(table, columns, ""); }     
        public string BuildSQL(string table, string columns, string wherePart) { return BuildSQL(table, columns, wherePart, ""); }     
        public string BuildSQL(string table, string columns, string wherePart, string orderBy) { return BuildSQL(table, columns, wherePart, orderBy, ""); }     
        public string BuildSQL(string table, string columns, string wherePart, string orderBy, string limit)     
        {     
            return String.Format("SELCT {0} FROM ...)", columns);     
        }     

allein um die einfachen Fälle abzudecken, bräuchtet Ihr 4 weitere Methoden für die Parameterüberladung, von den Fällen wie z.B. Tabelle und Order By mal abgesehen.

Wollen wir das? Nein, darum das ganze nochmal

    
public string BuildSQL(string table, string columns="*", string wherePart="", string orderBy="", string limit=""){ … }     
BuildSQL("User");     
BuildSQL("User", "Name");     
BuildSQL("User", limit: "10");     
BuildSQL("User", orderBy:"Name", limit:"20", columns:"Name");     

Mit Hilfe der optionalen Parameter, brauchen wir jetzt nur noch eine Methode um das Ganze zu bewerkstelligen.

Wichtig Parameter die optional sein sollen, müssen unbedingt am Ende der Parameterliste stehen. Zusätzlich können wir in diesem Beispiel eine weitere Neuerung sehen.

Die benannten Parameter, helfen uns nicht nur beim Aufruf auf manche Parameter zu verzichten, sondern gibt es uns auch eine neue Art der Übersicht, so dass man sobald man sich den Aufruf anschaut, auf den ersten Blick sofort erkennen kann, welcher Wert in welchen Übergabe Parameter übergeben wird (natürlich nur solange eure Parameter eine sprechende Bezeichnung haben)

Was euch in diesem Beispiel ebenfalls auffallen sollte ist, dass die Reihenfolge wie man die Parameter angibt ist eigentlich nicht nur nicht relevant ist, sondern das die Reihenfolge wie man die Parameter angibt sogar beachtet wird.

    
static void Main(string[] args)     
{     
    var p = new Program();  

    int n = 3;    
    p.WriteSomething(y:n++, x:n);     
}  

public void WriteSomething(int x, int y)    
{     
    Console.WriteLine("x:{0}, y:{1}", x, y);     
    Console.ReadLine();     
}     

Die Ausgabe lautet, für manch einen unerwartet

x:4, y:3    wie gesagt die Reihenfolge spielt eine Rolle

  • erst wird dem Parameter y der Wert von n also 3 zugewiesen
  • dann wird n Inkrementiert
  • und erst dann dem x Parameter der inkrementierte Wert 4

 

An sich also ein schönes Feature, … doch wo liegt denn bei den optionalen Parameter eine Gefahr???

 

 

Um dieses Problem zu demonstrieren muss ich eine kleine Änderung an dem Projekt vornehmen.

Wir lagern die Methode inkl. der Defaultparameter in eine eigene DLL aus, kompilieren und schauen uns den erzeugten IL-Code an.

Hinweis:

Bisher, habe ich  für solche Zwecke immer den Reflector benutzt, doch da Redgate sich dazu entschlossen hat, zukünftig  35 $ für dieses Produkt zu nehmen, gewöhne ich mich jetzt schon an die Alternative

ILSpy. Entwickelt wird dieses Tool von den gleichen Entwicklern die auch die IDE SharpDevelop hervorgebracht haben.

 

Dieser kleine Ausschnitt, zeigt uns nun den erzeugten IL-Code der Methode.

IL-Code-1

Das komische daran ist nur, dass ich an dieser Stelle weder etwas von den optionalen Parametern noch von den Defaultwerten entdecken kann. 

(Hmm, was macht der Compiler denn da, oder habe ich die falsche DLL benutzt?)

Nein, die Assembly war auf jeden Fall die richtige

schauen wir uns einfach mal, die ausführbare Datei im ILSpy an (in der Hoffnung an das wir an dieser Stelle mehr sehen)

Also ILSpy starten, Exe laden und dann suchen wir mal die Stelle an der die Methode (z.B. BuildSQL) aufgerufen wird

IL-Code-2

So da haben wir ja zumindest schon einmal drei der Aufrufe

 

Wenn wir uns jetzt nochmal die C# Varianten in Gedächtnis rufen

    
//Zeile IL_0008 – IL_0026     
BuildSQL("User");     
//Zeile IL_0027 – IL_0046     
BuildSQL("User", "Name");     
//Zeile IL_0047 – IL_0064     
BuildSQL("User", limit: "10");     


in den Zeilen 8 – 26 erkennen wir, dass obwohl wir in unserm C# Code nur den Wert User an den Parameter table übergeben haben, zeigt der IL-Code das wir der Methode BuildSQL immer 5 Werte übergeben.

in diesem Beispiel können wir auch erkennen, was mit den Default werten passiert, Diese werden wie zb in der Zeile IL_000d bereits übergeben- 

 

Fassen wir diese Erkenntnisse noch einmal kurz zusammen

  • das Feature der benannten Parameter erlaubt es uns, Parameter beim Aufruf Namentlich zu benennen 
  • das Feature optionale Parameter, erlaubt es uns beim Aufruf einer Methode verschiedene Parameter nicht zu versorgen
  • Defaultparameter erlauben es die Defaultwerte zu bestimmen, die immer dann benutzt werden wenn wir nichts übergeben
  • Wenn man sich den erzeugten IL-Code anschaut, sieht man zumindest bei der Methode BuildSQL keine Veränderung im Gegensatz zu einer  ‘normalen’ Methode

 

Wenn man sich den IL-Code anschaut, erkennt man jedoch, dass diese neuen Möglichkeiten sind nur syntaktischer Zucker sind, denn in Wirklichkeit übergeben wir immer jedem einzelnen Parameter einen Wert

Und genau an dieser Stelle, sieht der ein oder andere auch schon das Problem

 

Wenn wir nun eine Anwendung entwickeln, die ähnlich der Bespielapplikation aufgebaut ist. (eine ausführbare Datei und eine Assembly)

Hier befindet sich nun eine Methode X mit z.B. folgenden Parametern  (string, string, bool=true)  wobei der letzte Paramter ein Defaultparameter ist.

Die Applikation befindet sich bei einem Kunden im Einsatz, bis zu dem Tage an dem der Kunde anruft und einen Fehler meldet

Schnell kann man den Fehler in der Methode X ausfindig machen und stellt fest, der Defaultparameter müsste eigentlich false und nicht true sein.

Also ändert man den Defaultparameter und testet die nun veränderte Methode … Da wir Ihr ja nur die Library verändert haben, wird auch nur diese beim Kunden eingespielt

Jedoch beim Kunden ist dieser Fehler nicht verschwunden, … Ihr erinnert euch an diesen Blogeintrag und es fällt euch wieder ein …

 

 

Durch das Umsetzten des Defaultparameters, habt Ihr nicht unbedingt die Assembly verändert in der sich eure cs Datei befindet, sondern jedem einzelne Assembly die diese eine Methode aufruft!

Visual Studio Async CTP
Ein weiterer Bericht von der Basta Spring.

Diese Library gibt euch ein Vorgeschmack, auf das was in der nächsten Version des Framework kommen wird.

Die bisherigen Möglichkeiten einen Asyncronen Aufruf durchzuführen, ist mit den heutigen Mitteln zwar nicht besonders schwierig, jedoch schrecken manche Entwickler immer noch davor davor zurück, einen Vorgang asyncron durchzuführen.

Warum sollte ich Vorgänge asyncron durchführen?

Bei einem Vorgang der nur wenige Millisekunden dauert, muss ich den Vorgang nicht zwangsläufig  asyncron durchführen, jedoch sobald der Vorgang länger dauert oder nicht abzusehen ist wie lang der jeweilige Vorgang dauern könnte, sollte man es machen.

Den Fakt ist, das User Interface sollte auch während einer länger laufenden Aktion, immer bedienbar bleiben!! den so ein Dialog verstärkt das Vertrauen eines Users nicht wirklich!Reagiertnicht

Wie funktioniert das ganze

Beispiel ohne Library am Beispiel des WebClient NS: System.Net

  static void Main(string[] args)
  {
         string url = "http://www.Microsoft.de";
         var client = new WebClient();
         client.DownloadDataCompleted += client_DownloadDataCompleted;

         client.DownloadDataAsync(new Uri(url));

         //an dieser Stelle sind noch keine daten vorhanden
         Console.ReadLine();
         Console.WriteLine("<END>");
      }

      static void client_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
      {
          //jetzt kommen die Daten 

          string strData = Encoding.Default.GetString(e.Result);

          Console.WriteLine(strData);
      }
 <pre>

Durch diese paar Zeilen Code würde die UI während des Herunterladen immer zugreifbar bleiben.

Beispiel mit Library

<span class="lnum"></span>
  static void Main(string[] args)
  {
        DownloadData();

        //an dieser Stelle sind noch keine daten vorhanden
        Console.ReadLine();
        Console.WriteLine("<END>");
  }

  private async static void DownloadData()
  {
         string url = "http://www.Microsoft.de";
         var client = new WebClient();
	 //Zeile 16	 
         string strData = await client.DownloadDataAsync(new Uri(url));
		 
         Console.WriteLine(strData);
  }
 
An diesem Beispiel erkennen wir, das wir durch die beiden neuen Schlüsselwörter
async und Await das gleiche Ergebnis erreichen können.
Nur der Code sieht viel schöner aus!
 
Ja jetzt höre ich euch schon, was erreichen wir damit der Code bleibt an der Zeile 16
doch stehen bis er fertig ist, jedoch so ist es nicht.
 
Das Programm läuft genau so wie im ersten Beispiel.
 
DownloadData() wird bis zur Zeile 16 Ausgeführt und das Schlüsselwort Async bewirkt, dass das Programm 
in der Main Methode solange Fortgesetzt wird bis die Daten heruntergeladen wurden.
Sobald die Daten vorliegen, läuft das Programm dann ab Zeile 16 weiter. 
 
Link: Visual Studio Async CTP
Posted: Feb 26 2011, 04:02 von Lars Schmitt | mit no comments
Abgelegt unter: ,
zurück von der Basta

Ja so ist nun einmal, auch eine Basta geht leider einmal zu ende.

Ich hatte das Glück, dass ich die Basta Spring in der Zeit vom 22.Februar - 24.Februar in Darmstadt besuchen durfte. Eigentlich geht diese Konferenz ja über 5 Tage (22.Februar - 24.Februar) jedoch auch ohne die Workshops, kann man einige neue Erfahrungen und neue Sichtweisen mit nach Hause nehmen.

In der nächsten Zeit beabsichtige ich, einige dieser Informationen an euch weiterzugeben.

Also wenn Ihr gerade am überlegen seid, ob Ihr die nächste Basta besuchen wollt, mein Rat kann dann  nur JA lauten.

Posted: Feb 26 2011, 09:56 von Lars Schmitt | mit no comments
Abgelegt unter: