mardi 12 janvier 2010

Initialiser une structure complexe en C# - petite étude sur la lisibilité de code - partie III

Introduction
Suite des articles

Pour rappel, le but de cette série d'articles est de pouvoir initialiser une structure complexes en utilisant un code C# facile à lire et à maintenir. Quelque-chose de similaire (dans l'écriture) aux possibilités offertes par Python.
Bien qu'il soit préférable de lire les deux précédents articles, cela n'est pas nécessaire à la compréhension du code C# repris ci-dessous.

Les types anonymes
Petite définition du type anonyme
Les types anonymes n'ont pas de nom. Pour facilité la compréhension, le mot "type" peut-être remplacé par "classe".
Donc, il est possible de créer des instances de classe sans que cette dernière ait été explicitement décrite.
Les classes anonymes sont cependant beaucoup plus limitées que les classes habituelles.
Elles dérivent immédiatement de "object" et ne dispose que de membres.
A chaque field (champ) accessible dans une classe anonyme correspond une variable privée publiée par une auto-property.

Lors de l'utilisation de type anonymes, le mot clé "new" est utilisé sans spécifier le type de l'objet.
A la place, un property initializer {} est utilisé pour définir et initialiser la structure.

L'objet ainsi crée est stocké dans une référence à l'aide du mot clé "var", ce dernier permettant de bénéficier du typage implicite.

Les types anonymes produisent des classes et que les instances sont des objets, il est donc possible d'appliquer toutes les techniques applicables aux objets (stockage en array, reflexion, etc).

Exemple de type anonyme

var anAlbum = new { Name = "L'as du lavabo", Seconds = 187 };
Console.WriteLine( "name: {0}", anAlbum.Name );
Console.WriteLine( "Time: {0}", anAlbum.Seconds );

// Declaring an CD album as Anonymous type.
// Notice: 
//   1) The usage of var for Implicit Type  
//   2) The class type in not mentionned after the "new"
var CDAlbum = new
{
    Name = "This is it",
    Artist = "Jackson",
    Type = "Pop",
    Year = 2009,
    Info = "1/2",
    // Tracks are declared and stored within an array of anonymous type.
    // The class type is still not mentionned after the "new" and before the "[]"
    //   (array declaration)
    Tracks = new[] {
        // Each track is declared as an anonymous object
        new { Name = "Wonna Be startin' Somethin'", Seconds = 124 },
        new { Name = "Jam", Seconds = 341 },
        new { Name = "Human Nature", Seconds = 243 }
    }
};

Quatrième essai: Les types anomnymes
En utilisant les types anonymes (décrits ci-avant), il est possible de créer ma structure stockant la collection de CD (voir introduction de la partie I) sans alourdir le code avec des définitions de classes qui sont, dans ce cas, inutiles.
De surcroît, l'écrire est très compacte, lisible et aussi efficace que le script Python équivalent.

// Declaring my CD collection with anonymous type structure.
var CDs = new[] {
    // CD 1
    new { Name = "This is it", Artist = "Jackson", Type = "Pop", Year = 2009, Info = "1/2",
          Tracks = new[] { new { Name = "Wonna Be startin' Somethin'", Seconds = 124 },
                           new { Name = "Jam", Seconds = 341 },
                           new { Name = "Human Nature", Seconds = 243 } }
        },
    // CD 2
    new { Name = "Friends", Artist = "Tam-Tam", Type = "Capella", Year = 2007, Info = "Demo disc",
          Tracks = new[] { new { Name = "Sophie", Seconds = 248 },
                           new { Name = "Friends", Seconds = 178 },
                           new { Name = "Le dictionnaire", Seconds = 86 },
                           new { Name = "L'as du lavabo", Seconds = 187 } }
        },
    // CD 3
    new { Name = "History", Artist = "Jackson", Type = "Pop", Year = 2009, Info = "Continues, 2/2",
          Tracks = new[] { new { Name="Scream (duet with Janet Jackson)", Seconds=114},
                           new { Name="They don't care about us", Seconds=108 },
                           new { Name="Smile", Seconds=98},
                           new { Name="Money", Seconds=95} }
        }
};

// Display the result
foreach (var aCD in CDs) {
    Console.WriteLine("Name: {3}, Artist: {0}, Type: {1}, Year: {2}, Info: {4}",
                    aCD.Artist, aCD.Type, aCD.Year, aCD.Name, aCD.Info);

    String _Tracks;
    _Tracks = String.Join( "\n\t\t", 
               (from cdtrack
                in aCD.Tracks
                select "TrackName: " + cdtrack.Name + ", seconds:" + cdtrack.Seconds.ToString()
               ).ToArray<String>() );
    Console.WriteLine("\t\t" + _Tracks );
}

Références:

Aucun commentaire: