Frédéric Mélantois
C# 3.0 Beta, déclarations et initialisations simplifiées, regardons sous le capot !
Puisque le produit est encore en beta, portons un regard sur quelques nouveautés du langage et ce qui peut être généré par le compilateur c#.
Par Frédéric Mélantois publié le 25/06/2007 à 00:52, lu 4727 fois, 8 pages
 2 | Déclaration simplifiée des propriétés
Nous avons souvent recours au « refactoring » de Visual Studio 2005, pour mettre à disposition des propriétés publiques dans nos classes. L'écriture s'avère être lourde pour un modèle souvent répété :

private string _nom;

 

public string Nom

{

    get { return _nom; }

    set { _nom = value; }

}

Une avancée du langage c# permet de simplifier cette écriture par la syntaxe suivante :

public string Nom { get; set; }

Cette écriture permet de rendre le code plus limpide. On remarque bien évidemment qu'on se rapproche des définitions de propriétés dans les interfaces. A tel point que l'on aurait pu imaginer que le fait d'implémenter une interface comportant des propriétés puisse nous décharger de la nécessité d'écrire ces propriétés dans la classe elle-même. Le compilateur C# aurait pu prendre en charge l'écriture de ces définitions dans l'assembly. Heureusement, pour un souci de lisibilité du code, il n'en est rien.

La première question que l'on peut se poser est évidemment la question de la performance. En tant que développeur c#, langage de haut niveau, si j'utilise cette syntaxe, ne vais-je pas avoir un peu plus de lenteur à l'exécution ? Le meilleur moyen de le vérifier est de décompiler l'assembly pour observer les différences entre un code écrit « à l'ancienne » et un code « nouvelle façon simplifiée».
Créons deux classes identiques avec une propriété déclarée différemment :

public class GeekOne

{

    public string Nom { get; set; }

}

 

public class GeekTwo

{

 

    private string _nom;

 

    public string Nom

    {

        get { return _nom; }

        set { _nom = value; }

    }

}

Compilons puis désassemblons via l'outil en ligne de commande ildasm.exe :

ildasm monassembly.exe /out:source.il

Il nous suffit d'analyser le code IL produit et comparer nos deux portions de codes. Avec la syntaxe de C# 3.0, le code IL de la propriété est le suivant :

.class public auto ansi beforefieldinit ConsoleApplication1.GeekOne

       extends [mscorlib]System.Object

{

  .field private string '<>k__AutomaticallyGeneratedPropertyField0'

  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )

  .method public hidebysig specialname instance string

          get_Nom() cil managed

  {

    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )

    // Code size       11 (0xb)

    .maxstack  1

    .locals init (string V_0)

    IL_0000:  ldarg.0

    IL_0001:  ldfld      string ConsoleApplication1.GeekOne::'<>k__AutomaticallyGeneratedPropertyField0'

    IL_0006:  stloc.0

    IL_0007:  br.s       IL_0009

 

    IL_0009:  ldloc.0

    IL_000a:  ret

  }

 

  .method public hidebysig specialname instance void

          set_Nom(string 'value') cil managed

  {

    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 

    // Code size       8 (0x8)

    .maxstack  8

    IL_0000:  ldarg.0

    IL_0001:  ldarg.1

    IL_0002:  stfld      string ConsoleApplication1.GeekOne::'<>k__AutomaticallyGeneratedPropertyField0'

    IL_0007:  ret

  }

 

  .method public hidebysig specialname rtspecialname

          instance void  .ctor() cil managed

  {

    // Code size       7 (0x7)

    .maxstack  8

    IL_0000:  ldarg.0

    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()

    IL_0006:  ret

  }

 

  .property instance string Nom()

  {

    .get instance string ConsoleApplication1.GeekOne::get_Nom()

    .set instance void ConsoleApplication1.GeekOne::set_Nom(string)

  }

}

La source IL correspondant au code c# écrit « à l'ancienne » est la suivante :

.class public auto ansi beforefieldinit ConsoleApplication1.GeekTwo

       extends [mscorlib]System.Object

{

  .field private string _nom

  .method public hidebysig specialname instance string

          get_Nom() cil managed

  {

    // Code size       12 (0xc)

    .maxstack  1

    .locals init ([0] string CS$1$0000)

    IL_0001:  ldarg.0

    IL_0002:  ldfld      string ConsoleApplication1.GeekTwo::_nom

    IL_0007:  stloc.0

    IL_0008:  br.s       IL_000a

 

    IL_000a:  ldloc.0

    IL_000b:  ret

  }

 

  .method public hidebysig specialname instance void

          set_Nom(string 'value') cil managed

  {

    // Code size       9 (0x9)

    .maxstack  8

    IL_0001:  ldarg.0

    IL_0002:  ldarg.1

    IL_0003:  stfld      string ConsoleApplication1.GeekTwo::_nom

    IL_0008:  ret

  }

 

  .method public hidebysig specialname rtspecialname

          instance void  .ctor() cil managed

  {

    // Code size       7 (0x7)

    .maxstack  8

    IL_0000:  ldarg.0

    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()

    IL_0006:  ret

  }

 

  .property instance string Nom()

  {

    .get instance string ConsoleApplication1.GeekTwo::get_Nom()

    .set instance void ConsoleApplication1.GeekTwo::set_Nom(string)

  }

}

Très vite, on s'aperçoit qu'il n'y a pas de différence mis à part le nom du champ « _nom » au lieu de « '<>k__AutomaticallyGeneratedPropertyField0' » et un attribut (System.Runtime.CompilerServices.CompilerGeneratedAttribute) indiquant les parties de code généré par le compilateur. Autrement dit, il n'y a pas de différence à l'exécution sur le code machine produit.

Pour ceux qui ne sont pas vraiment familiers à l'IL, voici ce que nous donne l'utilitaire Reflector :

[CompilerGenerated]

private string <>k__AutomaticallyGeneratedPropertyField0;

 

public string Nom

{

    [CompilerGenerated]

    get

    {

        return this.<>k__AutomaticallyGeneratedPropertyField0;

    }

    [CompilerGenerated]

    set

    {

        this.<>k__AutomaticallyGeneratedPropertyField0 = value;

    }

}

 
» Démarrer une discussion
 
Discussion démarée par Malkuth le 24/07/2007 à 03:11, 2 commentaire(s).
Discussion démarée par vjacquet le 25/06/2007 à 17:42, 4 commentaire(s).