Peter Bucher - Mein Experiment, meine Spielereien, meine Welt...   ·   Stefan Falz   ·   Jürgen Gutsch   ·   Golo Roden   ·   ASP.NET Zone   ·   Microsoft ASP.NET
Willkommen bei ASP.NET Zone. Anmelden | Registrieren | Hilfe

Alles var – oder nicht?

Am 13. Oktober 2008 haben Golo Roden und ich unter dem Titel Noch Fragen, Roden? Ja, Bucher! angekündigt, jeweils zum ersten eines jeden Monats einen Kommentar zu einem vorab gemeinsam gewählten Thema verfassen zu wollen. Bisher sind in dieser Reihe folgende Kommentare erschienen:

Heute, am 1. September 2009, ist es nun wieder so weit, und unser Thema für diesen Monat lautet:

Alles var – oder nicht?

So wohl Golo wie auch ich haben uns unabhängig voneinander im Vorfeld unsere Gedanken gemacht, wie wir diesem Thema gegenüberstehen. Golos Kommentar findet sich zeitgleich in seinem Blog, folgend nun mein Kommentar zu diesem Thema:

Nein, werter Leser, das ist kein Rechtschreibefehler, das ist eine wirklich vwa(h)re Geschichte.
Scherz beiseite, los gehts… ;-)

Einleitung

Mit C# 3.0 kam ein neues Schlüsselwort names var hinzu, nur was hat es damit auf sich?

Es handelt sich dabei weder um ein spät gebundenen noch um einen Variant Typ, wie man ihn bspw. von Scriptsprachen her kennt, sondern um ein Feature das erst die Nutzung von anonymen Typen möglich macht.

Einfach gesagt heisst das, dass der Compiler den Typ auf der linken Seite vom Ausdruck auf der rechten Seite ableitet.
Also sind die Variablen immer stark typisiert und zwar zur Kompilezeit, nicht erst zur Laufzeit.

Was ist der Sinn des ganzen, bzw. wieso wurde dieses Feature integriert?

Im Zuge der Entwicklung von LINQ wurden die anonymen Typen eingefügt um eine Projektion der Daten auf irgendeine Objektstruktur zu ermöglichen, ohne dazu immer wieder neue Datenhaltungsklassen erstellen zu müssen.

Damit ist dann bspw. sowas möglich:

List<string> data = new List<string>
{
  "Patrick:24",
  "Stefan:16",
  "Jörg:22"
};

var persons = from dataEntry in data
              let splitted = dataEntry.Split(new[] { ':' })
              select new
              {
                Name = splitted[0],
                Age = int.Parse(splitted[1])
              };

foreach (var person in persons)
{
  Console.WriteLine("Name: {0}, Age: {1}", person.Name, person.Age);
}

Dabei ist der Typ von persons IEnumerable<T> wobei T in Visual Studio als "a” für Anonymous gekennzeichnet wird.
Und dementsprechend ist jeder Eintrag in dieser durchlaufbaren Menge ein anonymer Typ, der im Hintergrund vom Kompiler generiert und bereitgestellt wird.

Die Eigenschaft “Name” ist – wer hätte es gedacht – vom Typ string und “Age” vom Datentyp int.

Wo kann var überall eingesetzt werden?

Das Schlüsselwort kann nur für lokale Variablen genutzt werden, so sind automatisch auch anonyme Typen nur in diesem Bereich nutzbar. D.h. es können auch keine anonymen Typen über Methodengrenzen hinaus übergeben werden.

Wo macht es Sinn var einzusetzen und wann ist ein var mehr zuviel?

Das ist eine spannende Frage und eigentlich der Kernpunkt dieses Streitgespräches.
Hier einfach mal ein paar Beispiele:

private void SetProperties()
{
  var collectionMapping = this.CollectionMapping;

  if(collectionMapping.Count() > 0)
  {
    collectionMapping.Clear();
  }
}

private void SetProperties()
{
  ICollectionMapping collectionMapping = this.CollectionMapping;

  if(collectionMapping.Count() > 0)
  {
    collectionMapping.Clear();
  }
}

public static void RegisterType()
{
    var objectToXElement = BuildObjectToXElementFunc<TEntity>();
    var xElementToObject = BuildXElementToObjectFunc<TEntity>();

    RegisterType(objectToXElement, xElementToObject);
}

public static void RegisterType()
{
    Func<TEntity, XElement> objectToXElement = BuildObjectToXElementFunc<TEntity>();
    Func<XElement, TEntity> xElementToObject = BuildXElementToObjectFunc<TEntity>();

    RegisterType(objectToXElement, xElementToObject);
}

oder sowas:

var wtf = GetPattern();

vs

Pattern pattern = GetPattern();

In der ersten Methode wird var benutzt und in der folgenden dann nicht mehr.
Ich habe die Beispiele extra so gewählt, denn wenn in diesen Methoden var benutzt wird, sieht man auf den ersten Blick (ohne die Maus zu benutzen, oder einen verrenkten Shortcut) nicht, um was für einen Typen es sich hier handelt.

Und das ist natürlich ein sehr wichtiger Aspekt.
Denn was nützt mir das weniger schreiben und weniger Code, wenn ich beim lesen – was übrigens vom Zeitaufwand deutlich mehr ist als das Schreiben – nicht mehr auf den ersten Blick erkennen kann, was für Typen das sind.

Man sollte das Schlüsselwort im Regelfall wirklich nur einsetzen um die anonymen Typen benutzen zu können.

Ausnahme wenn es sich um eine lange Typdefinition handelt _und_ initialisiert wird

Ich für meinen Teil halte es so, das ich es eben dann benutze und zusätzlich auch noch in Fällen bei denen die Initialisierung (nicht Zuweisung) rechts daneben steht.

Und das auch nur wenn es sich um eine lange und komplexere Typbezeichnung handelt, das sind dann meistens solche mit generischem Typparameter, Beispiel:

public void Foo()
{
    Dictionary<string, Person> persons = new Dictionary<string, Person> {…}
}

public void Foo()
{
    var persons = new Dictionary<string, Person> {…}
}

Durch den sprechenden Namen und dadurch das die Initialisierung der Variable und so auch die implizite Zuweisung des Types auf der rechten ist, kann das auch gut gelesen werden und ist praktikabel finde ich.

Diese Anwendung hilft auch Redundanzen zu vermeiden. Wenn man bspw. die Initialisierung änderet ist der Typ auch automatisch angepasst.
Das ist ein netter Nebeneffekt, kann aber auch böse enden, wenn man sich dessen nicht bewusst ist, das Interface gleich ist, aber sich die Methoden / Eigenschaften die später aufgerufen werden, anders verhalten.

Ausnahme wenn es um LINQ Abfragen handelt

Bei LINQ Abfragen benötigt es kein var, wenn keine anonymen Typen genutzt werden.
Allerdings halte ich es auch bei LINQ-Abfragen so, dass ich meistens var benutze.
Denn mit guten Namen und im kleinen Kontext gehalten ist klar und verständlich was rüber kommt. Grösster Vorteil hierbei ist auch die automatische Anpassung des Types.

Dies kommt in diesem Fall sehr zum Vorschein, denn durch Projektion kann sich der Rückgabetyp schnell ändern, obwohl die Eigenschaften bspw. gleich bleiben.

public void Foo()
{
    IEnumerable<Person> persons = from person in list.Persons where person.Age > 20 select person;
}

public void Foo()
{
    var persons = from person in list.Persons where person.Age > 20 select person;
}

Das wars auch schon mit den Ausnahmen. Alles andere ist in meinen Augen nicht mehr lesbar und auch nicht gerechtfertigt.
Ich finde es schon ein wenig beängstigend, wenn ich im Web (Auch von Microsoft) Beispiele sehen, die Zahlen und Zeichenfolgen in 20, 30 Zeilen nur mit var arbeiten.
Wenn die Variablennamen dann noch schlecht gewählt, gute Nacht.

Was denkt ihr über die Sache und vorallem über meine genannten Ausnahmen?

Veröffentlicht Dienstag, 1. September 2009 09:37 von Peter Bucher
Abgelegt unter: , , , ,

Kommentare

# re: Alles var – oder nicht?

Kurz und knapp. Ich mag kein var...

Gruss

Stefan Koelle

Mittwoch, 2. September 2009 22:27 by skoelle

# Wieviel Sinn machen Unittests?

Am 13. Oktober 2008 haben Golo Roden und ich unter dem Titel Noch Fragen, Golo? Ja, Bucher! angekündigt,

Montag, 2. November 2009 09:43 by Peter Bucher

# Reflection – Fluch oder Segen?

Am 13. Oktober 2008 haben Golo Roden und ich unter dem Titel Noch Fragen, Roden? Ja, Bucher! angekündigt,

Dienstag, 1. Dezember 2009 21:03 by Peter Bucher

# this oder kein this

Am 13. Oktober 2008 haben Golo Roden und ich unter dem Titel Noch Fragen, Roden? Ja, Bucher! angekündigt,

Dienstag, 16. Februar 2010 21:30 by Peter Bucher

# Felder vs Eigenschaften

Am 13. Oktober 2008 haben Golo Roden und ich unter dem Titel Noch Fragen, Roden? Ja, Bucher! angekündigt,

Sonntag, 14. März 2010 16:53 by Peter Bucher

# Abstraktion

Am 13. Oktober 2008 haben Golo Roden und ich unter dem Titel Noch Fragen, Roden? Ja, Bucher! angekündigt,

Freitag, 9. April 2010 13:22 by Peter Bucher
Anonyme Kommentare sind nicht zugelassen