vendredi 8 janvier 2010

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

Introduction
En vue de m'exercer un peu à la manipulation d'objets XML sous .Net, j'ai voulu créer facilement une structure complexe en mémoire dans le but de pouvoir, par la suite, en faire un document XML.
J'ai donc choisi de décrire une collection de CD.

Puisque la structure était complexe, j'ai donc opté pour l'utilisation de classes et structures afin faciliter la création des éléments et essayer d'aboutir à un code LIMPIDE.
Le but étant de pouvoir, à terme utilisé des expressions LinQ et List.foreach pour m'aider à créer mon document XML.

En créant cette structure complexe, j'ai également voulu pouvoir l'initialiser facilement, rapidement mais SURTOUT en ayant un code FACILE A LIRE (et donc facile à maintenir).
Je voudrais aboutir à quelque-chose d'aussi clair que du code Python... car dans ce domaine, je dois avouer que Python dispose de quelques avantages.

Premier jet
A l'aide de la déclaration de CD et CDTrack (voir plus bas), il est possible d'initialiser ma collection avec le code suivant:

// Use a class structure to easily create structured data collection
List<CD> _CDs = new List<CD>();
_CDs.Add(new CD( new CDTrack() { Name = "Wonna Be startin' Somethin'", Seconds = 124 },
                  new CDTrack() { Name = "Jam", Seconds = 341 },
                  new CDTrack() { Name = "Human Nature", Seconds = 243 }
                 ) { Name="This is it", Artist = "Jackson", Type="Pop", Year=2009, Info="1/2" }
         );
_CDs.Add(new CD(new CDTrack() { Name = "Sophie", Seconds = 248 },
                  new CDTrack() { Name = "Friends", Seconds = 178 },
                  new CDTrack() { Name = "Le dictionnaire", Seconds = 86 },
                  new CDTrack() { Name = "L'as du lavabo", Seconds = 187 }
                 ) { Name = "Friends", Artist = "Tam-Tam", Type = "Capella", Year = 2007, Info = "Demo disc" }
         );

// Check the result:
foreach (CD cd in _CDs)
    Console.WriteLine(cd.ToString());

Conclusion
Bien que relativement compacte, le code de création reste un tantinet compliqué.
Les propriétés du CD arrivent après la création des instances de CDTrack.
Cela nuit de façon évidente à la lecture du code.

L'utilisation d'un "setter" pour la propriété Tracks permettrait certainement une écriture plus intelligible. C'est ce que je vais tester dès que possible. Je devrais également voir si les techniques de Class Inference peuvent faire quelque-chose pour moi.

Code des classes et structs
/// <summary>
/// Structure used to own information on a track
/// </summary>
struct CDTrack {
    public String Name { get; set; }
    public int Seconds{ get; set; }
}
/// <summary>
/// Class used to easily create a compact disk record
/// </summary>
class CD {
    private List<CDTrack> _tracks;

    public string Artist { get; set; }
    public string Type { get; set; }
    public int Year { get; set; }
    public String Name { get; set; }
    public String Info { get; set; }
    public List<CDTrack> Tracks { get { return _tracks; } }

    public CD() : base() {
        _tracks = new List<CDTrack>();
    }
    /// <summary>
    /// Create the description of a compact disk with Tracks.
    /// </summary>
    /// <param name="tracks">List of TrackName + TrackTime (in minutes)</param>
    public CD( params CDTrack[] tracks ):this(){
        foreach (CDTrack item in tracks)
            _tracks.Add(item);
    }

    public override string ToString()
    {
        String _Tracks;
        _Tracks = String.Join( "\n\t\t", 
                       (from cdtrack
                        in Tracks
                        select "TrackName: " + cdtrack.Name + ", seconds:" + cdtrack.Seconds.ToString()
                       ).ToArray<String>() ); 
        return base.ToString()+" having the properties: "+
            String.Format("\n  Name: {3}, Artist: {0}, Type: {1}, Year: {2}, Info: {4}",
                            Artist, Type, Year, Name, Info )+ "\n\t\t" + _Tracks;
    }
}

Aucun commentaire: