Blog de Julien Dollon (MVP)

Consultant / Formateur .NET

Julien Dollon

Consultant/formateur .NET pour I'FORM/Exakis et Full Professor SUPINFO.

Responsable de la communauté Dotnet-France ainsi que nommé Most Valuable Professional, je participe activement à la communauté Microsoft.


 

Mon CV de Consultant/Formateur .NET

Mon Transcript de Formateur .NET

 


 
 
 
 
Official INETA Logo
 
IForm

[.NET] CLR 4.0 (Code Contract, MEF, DLR & Parallel Extensions)

Visual Studio 2010 vient de sortir et il est temps pour moi de m’interesser à la CLR 4.0.

La CLR 4.0 n’est pas un simple ajout de fonctionnalités comme le Framework 3.0 ou 3.5 mais bien une nouvelle entité.

clr

La CLR permet de développer avec de nouveaux langages comme IronPython, F#…

Il est aussi possible de faire tourner la CLR 2.0 dans le même processus que la CLR 4.0 contrairement à l’ancienne CLR, on appelle ça le “In Process Side by Side” SxS.

L’interopabilité est améliorée grâce à un générateur P/Invoke (P/Invoke Interop Assistant) disponible sur codeplex ici.

Il en va de même pour le garbage collector qui a lui aussi le droit à une petite rénovation (GC server, GC client en background pour éviter de “freezer” le thread en cours…).

Nouveaux types

La CLR apporte de nouveaux types comme BigInteger, Tuple…

  • BigInteger (System.Numeric.BigInteger) vous permet d’utiliser de gros numériques suivant l’espace mémoire disponible.
  • Tuple vous permet d’avoir plusieurs valeurs de retour:
        private void Form1_Load(object sender, EventArgs e)
        {
            MessageBox.Show(GetResults(12, "juliend", 12.0).Item1.ToString());
        }

        public Tuple<int, string, double> GetResults(int arg1, string arg2, double arg3)
        {
            return new Tuple<int, string, double>(arg1, arg2, arg3);
        }

Code Contract

Il est désormais possible de développer avec du “Code Contract”. Cette nouvelle feature vous permet de poser des conditions avant (Requires), pendant (Invariant) et après (Ensures) une méthode.

Si la condition n’est pas respectée, une exception de type ContractException est levée.

Afin de profiter du Code Contract, il vous faut installer le Managed Contract Tools.

Puis direction les propriétés de votre projet pour activer cette fonctionnalité à l’éxécution et à la compilation:

codecontracts

Premier exemple:

Contract.Requires(condition booléenne) permet de poser une pré-condition à notre méthode. Ce qui déclenchera un warning lors de la compilation si elle n’est pas respectée et une erreur à l’éxécution.

        public string Echo(string s)
        {
            Contract.Requires(s != null);
            MessageBox.Show(s);
            return s;
        }

codecontracts2

De même pour Contract.Ensures(condition); pour les posts conditions et Contract. Invariant (condition); pour verifier une variable tout au long du déroulement du traitement.

Managed Extensibility Framework

Avant de commencer à vous présenter cette technologie, voici des liens à lire avant de poursuivre sur cet article:

Nous allons voir un cas pratique, conception d’une architecture logicielle d’un projet WPF composite avec un pattern MVVM pour chaque module.

Le but de MEF est de créer une application dite “composite” (un peu comme Prism v2). On va pouvoir ajouter des fonctionnalités à notre logiciel avec le simple ajout de dll dans un dossier spécifique.

Chaque module est indépendant et peux être architecturé de la façon que vous souhaitez (n-tiers, MVVM, MVC…).

Dans notre cas nous allons utiliser MVVM puisque c’est le pattern le plus en vogue pour WPF en ce moment. Vous trouverez ici la source du projet.

  • Création de l’interface commune à tous les modules dans une classlibrary
    public interface IModule
    {
        //Nom du module
        string Name { get; set; }   
    }
  • Développement de notre premier module

Ajoutez à votre solution un projet WPF, supprimez y le fichier app.xaml et changez les options de compilation:

mef1

Puis architecturez votre module grâce à MVVM comme expliqué dans cet article:

mef2

Puis appliquez certaines modifications à votre projet pour qu’il devienne un module MEF:

1/ ViewProduct doit implémenter IModule

    public partial class ViewProduct : UserControl, IModule
    {
        public ViewProduct()
        {
            InitializeComponent();
            DataContext = new ViewModelProduct();
        }

        string IModule.Name
        {
            get;
            set;
        }
    }

2/ Ajout de la référence System.ComponentModel.Composition à votre projet

mef3 

3/ Ajout de l’attribut Export et ExportMetaData au dessus de votre View:

    [Export(typeof(IModule))]   
    [ExportMetadata("Name", "Products")] 

A ce stade votre class library est configurée pour MEF

  • Création du projet principal qui chargera le module

Créez un projet WPF et ajoutez la référence au projet contenant IModule ainsi que System.ComponentModel.Composition.

Xaml:

 <StackPanel x:Name="stack"/>

Code Behind:

        public Window1()
        {
            InitializeComponent();
            AggregateCatalog catalog = new AggregateCatalog();
            catalog.Catalogs.Add(new DirectoryCatalog("."));
            this.modulesContainer = new CompositionContainer(catalog);
            this.modulesContainer.ComposeParts(this);

            foreach (var module in this.Modules)
            {
                this.stack.Children.Add(new TextBlock(){ Text = (String)module.Metadata["Name"] });
                this.stack.Children.Add(module.GetExportedObject() as UserControl);
            }
        }

        [Import(typeof(IModule))]
        public ExportCollection<IModule> Modules { get; set; }

        public CompositionContainer modulesContainer { get; set; }
DLR et C# 4

Grâce à la CLR4, nous voyons arriver une nouveauté telle que la DLR et C#4.

Qu’est-ce que la DLR ?

La DLR a été introduite afin de supporter les nouveaux langages dynamiques dans .net (IronPython, IronRuby et maintenant C# et VB.NET).

C’est une surcouche de la CLR, elle permet, entre autres, de remplacer la reflexion.

Le langage C# qui est un langage impératif/statique permet d’être performant, robuste et surtout analysable afin d’avoir des outils tels que l’intelliscence.

Les langages dynamiques tels que PHP ou JavaScript ont la puissance de pouvoir embarquer du code non compilé, par exemple en JavaScript:

    var1 = "juliend"; //Type string
    alert(var1);
    var1 = 2; //On passe en int
    alert(var1);

Vous remarquez que l’on peut typer à la volée la variable et que le compilateur ne peut déterminer son type.

Le JavaScript perd donc en sécurité mais on gagne en souplesse.

Les nouveautés du C#4

  • Paramètres
  • Dynamicité

csharp4

C#4 permet enfin d’avoir des paramètres par défaut comme en C++ mais aussi l’utilisation de paramètres nommés:

        public int Test(int i, int b = 2)
        {
            return i + b;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            MessageBox.Show(Test(2).ToString());
        }
        public int Test(int i, int b = 2)
        {
            return i + b;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            MessageBox.Show(Test(b:3, i:7).ToString());
        }

Avant C# 4, l’utilisation de la réfléxion était fréquente. Par exemple si nous avons une variable dont on ne connait pas son type mais que nous savons qu’il existe la méthode HelloWord alors nous l’utilisions comme ceci:

    class Class1
    {
        public void HelloWord(string t)
        {
            MessageBox.Show("Hello " + t);
        }
    }
        public object GetObject()
        {
            return new Class1();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            object monobjet = this.GetObject();
            Type montype = monobjet.GetType();
            montype.InvokeMember("HelloWord",
            BindingFlags.Default |
            BindingFlags.Public | BindingFlags.Public |
            BindingFlags.Instance | BindingFlags.InvokeMethod, 
            null, monobjet, 
	    new object[] { "Test" });
        }

Il est désormais possible d’utiliser la DLR pour remplacer la réfléxion, voici comment faire (toujours avec Class1):

            dynamic monobjet = this.GetObject();
            monobjet.HelloWord("test");

La méthode HelloWord ne possède pas d’intelliscence car c’est à l’éxécution qu’il va générer de la réfléxion (compilation à la volée).

Attention à ne pas abuser de ce type (comme en PHP par exemple) pour ne pas se retrouver à faire:

            dynamic monobjet = "lol";
            monobjet = 2;
            MessageBox.Show(monobjet.ToString());

Parallel Extensions (Task Parallel Library, Parallel Linq, Parallel Debugger tool)

La programmation parallèle s’impose de plus en plus puisque nos CPU sont souvent double coeur voir +.

La programmation parrallèle c’est quoi ? C’est la possibilité d’exploiter ces coeurs dans le code de tous les jours.

Cependant, cela implique d’utiliser des deadlocks, des mutex etc… et cela devient vite compliqué.

Parallel Extensions anciennement appelé ParallelFX va nous permettre de faciliter tous ces mécanismes.

Task Parallel Library (TPL)

Prenons comme exemple une boucle qui parcoure des objets (de façon ridicule, le but étant que le temps d’éxécution soit lent):

            Stopwatch watch = Stopwatch.StartNew();
            foreach (Utilisateur item in mesUsers)
            {
                foreach (Role r in mesRoles)
                    if (r.ID.Equals(item.Role.ID))
                    {
                        for (i = 0; i < 1000; i++)
                        {
                            b++;
                        }
                    }
            }
            watch.Stop();
            MessageBox.Show(watch.ElapsedMilliseconds.ToString());

parallel

Nous allons maintenant utiliser la programmation parallèle afin d’accèlerer notre code. Pour cela, le framework nous met à disposition la classe Parallel contenant la méthode statique ForEach.

L’un des problèmes de ce code est que la variable b risque de ne pas contenir la bonne valeur (plusieurs threads incrémentant en même temps par exemple).

Pour cela on contourne le problème avec la classe InterLocked qui incrémentera notre variable de façon atomique.

            watch = Stopwatch.StartNew();
            //Syntaxe: Parallel.ForEach<Type à parcourir>
            //Puis n=> est une expression lambda
            Parallel.ForEach<Utilisateur>(mesUsers, item =>
            {
                Parallel.ForEach<Role>(mesRoles, r =>
                {
                    if (r.ID.Equals(item.Role.ID))
                    {
                        Parallel.For(0, 1000, z =>
                        {
                            Interlocked.Increment(ref b);
                        });
                    }
                });
            });
            watch.Stop();

parallel2

Notre boucle est désormais réalisée en programmation parallèle. Vous remarquez cependant que l’on perd du temps plutôt qu’en gagner !! En effet, les parallèles extensions mettent en place beaucoup de chose pour réaliser votre boucle, chose qui n’est pas intéressante pour aussi peu de données.

Le gain de temps aurait pu s’effectuer si j’avais eu plus de traitement à faire dans mes boucles.

Parallel Linq (PLINQ)

Il existe la possibilité de paralléliser les requêtes Linq-To-Xml et Linq-To-Object.

Par exemple:

            Stopwatch watch = Stopwatch.StartNew();
            List<Utilisateur> mesUsers2 = (from u in mesUsers
                                           orderby u.Login ascending
                                           select u).ToList();
            watch.Stop();
            MessageBox.Show(watch.ElapsedMilliseconds.ToString());
            watch = Stopwatch.StartNew();
            mesUsers2 = (from u in mesUsers.AsParallel()
                         orderby u.Login ascending
                         select u).ToList();
            watch.Stop();
            MessageBox.Show(watch.ElapsedMilliseconds.ToString());

Le code effectue un tri sur une liste, l’un en Linq et l’autre en PLinq grâce à .AsParallel().

Vous pouvez constatez que dans les deux cas, tous les processeurs sont utilisés sauf que PLinq utilisera de façon optimale vos processeurs.

Plus vos listes sont grandes, plus l’utilisation de PLinq s’impose:

plinq Avec PLinq

plinq1Sans PLinq

Posted: Jun 09 2009, 18:33 by juliend | Comments (5) RSS comment feed |
  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: .NET | Général

Comments

Anael said:

Merci pour toutes ces informations :]

Qu'en est-il de MEF pour Silverlight?

# June 10 2009, 23:45

Julien Dollon said:

Très bonne question Smile Les evangelist MS ont fait un sondage sur twitter pour savoir si cela interessait du monde.
Affaire à suivre.

# June 11 2009, 00:01

Nk54 said:

Ok ... Je suis dans le MEF pour WPF ^^ go celui de silverlight now ... Enorme quand même Smile donne envie de dev des appli WPF Laughing

# November 03 2009, 00:14

Trikapalanet said:

Alors, il y a des nouvelles depuis ce fameux sondage?

# December 15 2009, 22:44

julien said:

Oui puisque MEF est maintenant supporté par Silverlight !
Je travaille sur un article là dessus ;)

# December 15 2009, 23:23

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading

captcha

*