Configuration d’un projet Angular 2.1.0 (version finale) avec Webpack

Avec l’automne, la version finale de Angular 2 est arrivé. Actuellement en version 2.1.0, le Framework JavaScript de Google offre beaucoup de fonctionnalités et mets le développement du stack Front-End des applications JavaScript sur un autre niveau super agréable, mais surtout fun.

Après avoir travaillé avec Angular 2 dépuis la version RC 2, j’ai suivi pas mal de changements dans le développement du Framework pendant les derniers mois.

Dans cet article-ci j’aimerais bien partager quelques conclusions pour un setup de base d’un application Single Page Angular 2.1.0. J’utilise le module bundler Webpack, NPM, le compiler de TypeScript et je montre le rechargement en live et comment on peut faire source mapping pour debugger l’application Angular 2 facilement dans un navigateur comme Chrome. En gros j’aimerais bien donner un aperçu de base aux questions suivants :

  • C’est quoi WebPack
  • Comment utiliser WebPack dans un appli Angular 2
  • Comment peut-on transpiler un appli en mode développement et production

Tout d’abord il faut créer la structure d’un projet, et l’ouvrir dans un editor de choix – ici Visual Studio Code, un très bon editor gratuit de Microsoft.

01-projectsetup

Les fichiers les plus importants sont package.json, tsconfig.json et webpack.config.js. Dans ceux fichiers-ci on retrouve la logique de configuration de ce projet-là.

{
  "name": "angular2-starter",
  "version": "0.1.0",
  "scripts": {
    "build": "webpack --progress",
    "build:prod": "webpack -p --progress",
    "postinstall": "typings install",
    "serve":"webpack-dev-server --inline --progress"
  },
  "dependencies": {
    "@angular/common": "~2.1.1",
    "@angular/compiler": "~2.1.1",
    "@angular/core": "~2.1.1",
    "@angular/http": "~2.1.1",
    "@angular/forms": "~2.1.1",
    "@angular/platform-browser": "~2.1.1",
    "@angular/platform-browser-dynamic": "~2.1.1",
    "@angular/router": "~3.1.1",
    "@angular/upgrade": "~2.1.1",
    "core-js": "^2.4.1",
    "reflect-metadata": "^0.1.8",
    "rxjs": "5.0.0-beta.12",
    "zone.js": "^0.6.25"
  },
  "devDependencies": {
    "html-webpack-plugin": "^2.24.1",
    "ts-loader": "^1.0.0",
    "typescript": "^2.0.7",
    "typings": "^1.5.0",
    "webpack": "^1.13.3",
    "webpack-dev-server": "^1.16.2"
  }
}

package.json est utilise pour charger les libraries dépendantes pour l’application. C’est conseillé de télécharger une version spécifique d’une bibliothèque pour ne pas briser l’application un jour. Néanmoins, ici j’utilise la dernière version des bibliothèques de la journée de la création. Ici on configure aussi les modes dev et prod.

{
    "compilerOptions": {
        "target": "es5",
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true
    }
}

tsconfig.json est important pour configurer TypeScript. Alors que c’est possible de développer un appli Angular 2 aussi avec JavaScript par exemple, on peut se vraiment faciliter la vie en utilisant TypeScript au lieu de JS.

On met le target de la transpilation sur es5, pour permettre aussi aux vieux navigateurs d’utiliser notre application. En plus il faut permettre quelques features de es6 de fonctionner dans notre TypeScript codage.

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    devtool: 'source-map',
    entry: './src/main.ts',
    output: {
        path: './dist',
        filename: 'app.bundle.js'
    },
    module: {
        loaders: [
            {test: /\.ts$/, loader: 'ts'}
        ]
    },
    resolve: {
        extensions: ['', '.js', '.ts']
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html'
        })
    ]
};

webpack.config.js, c’est le cœur de notre application, on configure WebPack avec.

En gros, WebPack c’est un module bundler, donc un outil qui permet de mettre le codage JS d’un server sur la côté du client. C’est-à-dire, WebPack peut faire pas mal de choses, et est riche de plugins. Ici on l’utilise pour :

  • Ajouter un lien vers bundle.js dans le index.html
  • Transpiler notre TS et Uglify notre JavaScript
  • Source Mapping (Map Js to TypeScript, pour debugger)
  • Live Reload

Au-dessous se trouvent les fichiers TypeScript et HTML qui sont utilisés par notre application. On utilise un main.ts pour bootstraper l’appli, un index.html, un app module et un premier component. Pour savoir plus autour de Angular 2, je conseille le Quick Start sur le site Web de Angular.

import 'core-js';
import 'reflect-metadata';
import 'zone.js/dist/zone';

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';

import { AppModule } from './app/app.module';

const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf8" />
        <title>Angular 2 Appli</title>
    </head>
    <body>
        <my-app>Chargement...</my-app>
    </body>
</html>
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';

@NgModule({
    imports: [
        BrowserModule
    ],
    declarations:[
        AppComponent
    ],
    bootstrap: [ AppComponent ]
})
export class AppModule { }
import { Component } from '@angular/core';

@Component({
    selector:'my-app',
    template:`
        <h1>Mon Appli</h1>
    `
})
export class AppComponent {
    
}

Avant que ça fonctionne, il faut exécuter quelques commands de NPM et WebPack dans notre console :

  1. npm install
  2. npm install –save-dev typescript
  3. npm install –save-dev typings
  4. npm install –save-dev webpack
  5. npm install –save-dev ts-loader
  6. npm install –save-dev html-webpack-plugin
  7. npm install –save-dev webpack-dev-server
  8. npm run build (npm run build:prod)
  9. webpack –progress
  10. npm run serve

Ben, c’est tout 😉 Depuis récemment il y a aussi le Angular CLI, qui peut faciliter le setup de base d’un appli Angular 2. Néanmoins, le CLI est encore en version Beta en ce moment.

De toute façon Angular 2 Rocks !!

Analyse statique de programmes – avec NDepend 6.3.0

En tant que programmeur on connait la situation, un nouveau projet, un nouveau défi. D’abord c’est toujours recommandable de se bien organiser pour mieux comprendre les exigences. Puis c’est souvent le cas, qu’il y a déjà une base de codage existant qu’il faut analyser. Bien sûr, Visual Studio donne plusieurs outils pour faciliter la vie d’un développeur. Par exemple l’utile « Code Analysis » qui peut être trouvé dans la « properties fenêtre » d’un projet et qui peut être utilisé avec Native Code et Managed Code. Néanmoins cette solution ne suffit pas toujours pour les besoins d’un développeur, c’est pourquoi il y a des alternatives sur le marché. Une telle solution, très populaire, est NDepend. En tout cas NDepend peut être utilisé avec Managed Code in .NET.

Une analyse statique d’un programme peut par exemple réduire les couts d’une erreur et le nombre des erreurs. Puis cela peut faciliter la maintenance d’un codage, parce que les développeurs découvrent la base de code et peuvent apprendre des bonnes pratiques.

Dans cet article je vais d’abord écrire le fond d’une analyse statique de programmes et pourquoi on peut recommander d’utiliser un outil comme NDepend, pour mieux comprendre un codage existent de Managed Code. Dans un article suivant on regardera utilisation et les expériences dans un projet réel avec ASP.NET MVC.

Tout d’abord, la théorie…

L’analyse statique de programmes est l’analyse d’un logiciel sans [réellement] l’exécuter (Contrairement, l’analyse d’un logiciel pendant son exécution qui s’appelle l’analyse dynamique). C’est-à-dire, l’analyse statique permets d’obtenir des informations sur un programme.

Les objectifs d’une telle analyse peuvent être :

  • Bug alerts,
  • Style de codage,
  • Adapter les » best practices » (Naming conventions etc.)
  • Vérification de la performance

Quelques paramètres qui peuvent être utiles sont :

  • Sont tous les méthodes écrit en Pascal Case ?
  • Y-a-t-il des null references dans le codage ?
  • Est-ce qu’il y a des instances d’une programmation « copier/collier « ?
  • C’est quoi le moyen montant de lignes de codage dans une classe / une méthode ?
  • Est-elle loosely ou tightly coupled, l’architecture ?
  • Quelles sont les classes à changer ?

C’est recommandable d’utiliser un outil comme NDepend pour faire une analyse statique d’un logiciel. NDepend aide à comprendre le codage ou mettre des informations outils à la disposition. Cette solution a été créé par Patrick Smacchia et s’est développée pendant les années pour être utilisé dans un environnement des entreprises.

NDepend, actuellement en version 6.3.0, offre entre autres :

  • Personnalisation et application des règles
  • Une représentation visuel d’un codage
  • L’intégration dans un build
  • Trace de changements

Un premier demo de NDepend peut être télécharge sous NDepend.com et ajouté au Visual Studio en tant que Add-On. Le site web offre une bonne documentation. Dans un prochain article, je vais jeter un coup d’œil sur l’utilisation dans un projet réel.

Les 3 types de Dependency Injection

Récemment j’ai écrit un article autour du concept de « Dependency Injection et Inversion of Control « avec une concentration sur l’utilisation d’un Container IoC.

Cette fois-ci, je veux donner un aperçu  des 3 différents possibilités, qu’on peut utiliser pour adapter le patron de conception Dependency Injection dans son codage :

  1. Constructor Injection
  2. Setter Injection
  3. Interface Injection

Constructor Injection

Passer une dépendance à la classe dépendant en utilisant le Constructor

namespace TypesDi
{
    class Program
    {
        static void Main(string[] args)
        {
            var coach = new Coach();

            var driver = new Driver(coach);
        }
    }

    public class Driver
    {
        private readonly IDriveable vehicle;

        public Driver(IDriveable vehicle)
        {
            this.vehicle = vehicle;
        }
    }

    public interface IDriveable {}

    public class Coach : IDriveable {}
}

Setter Injection

  • Créer un setter dans la classe dépendant
  • Utilisez un setter pour mettre la dépendance en place
namespace TypesDi
{
    class Program
    {
        static void Main(string[] args)
        {
            var coach = new Coach();

            var driver = new Driver();

            driver.MyVehicle = coach;

        }
    }

    public class Driver
    {
        public IDriveable MyVehicle { get; set; }
    }

    public interface IDriveable {}

    public class Coach : IDriveable {}
}

Interface Injection

  • La classe dépendante mets en œuvre un interface
  • L’injector utilise l’interface pour mettre la dépendance en place
namespace TypesDi
{
    class Program
    {
        static void Main(string[] args)
        {
            var coach = new Coach();

            var driver = new Driver();

            ((IDriveable)driver).Inject(coach);
        }
    }

    public class Driver : IDriveable
    {
        private IDriveable vehicle;

        public void Inject(IDriveable vehicle)
        {
            this.vehicle = vehicle;
        }
    }

    public interface IDriveable
    {
        void Inject(IDriveable vehicle);
    }

    public class Coach : IDriveable
    {
        public void Inject(IDriveable vehicle)
        {
            throw new NotImplementedException();
        }
    }
}

 

Bref, IoC et DI en C# (…en utilisant Windsor Castle, pour la reine ;)

Avez-vous déjà écouté l’expression « Inversion of Control (IoC) « ou « Dependency Injection (DI) « mais vous ne savez pas exactement de quoi il s’agît ou pourquoi vous pourriez en avoir besoin ? Si c’est le cas, veuillez continuer à lire chère lectrice ou cher lecteur.

Tout d’abord, il y a une grande différence entre Dependency Injection et Inversion of Control. DI c’est un patron de conception, tandis que IoC c’est plutôt un mécanisme, ou un framework utilisé pour injecter automatiquement des dépendances. Castle Windsor, c’est un exemple pour un framework IoC.

Ben alors, et c’est quoi exactement Dependency Injection maintenant ? Laissez-moi vous donner une explication simple :

dependency injection

Disons, la reine du royaume du Commonwealth visite le Canada. Pour son tour du pays, elle a besoin d’un conducteur. La reine dit à son conducteur : « Allez, on y conduit de Montréal à Toronto «.

Bien sûr, le conducteur aura besoin d’un véhicule et va alors aller en chercher un, soit un 4×4 ou soit un Rolls Royce. De toute façon, la reine n’a aucune influence sur le choix du véhicule. Et ça pourrait être un problème, surtout si le conducteur va prendre un vieux coche au lieu du Rolls Royce.

La reine et le conducteur seront insatisfaites, lui parce qu’il doit choisir, et elle à cause de son choix. C’est à dire, il y aura une relation indésirable entre le conducteur et le véhicule. Donc ça serait beaucoup mieux, si la reine pourrait donner le véhicule désiré au conducteur et disait : « Allez, Go là-bas ! «  …Non ? 😉

En tout cas, le framework IoC s’occupe de toutes les dépendances qui pourraient apparaitre dans une telle relation.

D’accord, faisons-nous une clarification du exemple au-dessus avec un codage en C#, d’abord le patron de conception Dependency Injection :

namespace DiLaReine
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }

    public class Reine
    {
        public void GiveOrder()
        {
            var charles = new Conducteur();

            var rollsRoyce = new RollsRoyce();
            var coach = new HorseBuggy();

            charles.ExecuteOrder(rollsRoyce);
            charles.ExecuteOrder(coach);
        }
    }

    public class Conducteur
    {
        public void ExecuteOrder(IDriveable vehicule)
        {
            vehicule.Drive();
        }
    }

    public interface IDriveable
    {
        void Drive();
    }

    public class RollsRoyce : IDriveable
    {
        public void Drive()
        {
        }
    }

    public class HorseBuggy : IDriveable
    {
        public void Drive()
        {
        }
    }
}

En gros…
…résumons-nous : DI c’est rien d’autre que contrôler ou résoudre des dépendances d’une mise en œuvre, en travaillant avec des interfaces par exemple. Comme ça, on peut donner une dépendance à un composant ou une classe appelé pendant la période d’action.

Et pourquoi donc tout cela ? SOLID, surtout S et O => Sinlge Responsibility Principle et Open-Closed Principle. DI/IoC fait ça donc beaucoup plus facile de maintenir les dépendances entre les objets dans une application.

Par exemple si on crée un appli pour des platforms différentes, on peut abstraire le codage commun et ajouter des spécificités d’un platform pendant la période d’action.

CASTLE WINDSOR

castle windsor

Dans notre exemple si-dessus, on pourrait dire, que Castle Windsor c’est le garage, qui s’occupe du parc de véhicules. Mais avant qu’on continue, il faut comprendre qu’il y a une différence entre Inversion of Control et Inversion of Control Container.

Inversion of Control Container

Le principe en software design IoC, est un principe où un codage custom d’un logiciel peut recevoir des instructions en regardant l’état de répétition du logiciel. Les frameworks IoC, comme par exemple Windsor, Unity, Ninject ou Spring utilisent ce principe pour maintenir les objets d’un logiciel.

Cela c’est le travail d’un Inversion of Control Container, en bref. C’est-à-dire, un IoC Container utilise le principe IoC pour maintenir les classes d’un logiciel et leur cycle vital : la création,  la destruction, la configuration et leurs dépendances. Ça a l’avantage que les classes n’ont pas besoin d’obtenir ou configure les classes dont elles dépendent. Avantage : La flexibilité et le soulagement de la réutilisation et testabilité des classes d’un logicel

Exemple en utilisant Windsor

J’utilise un appli console simple. Dans le projet, il faut ajouter un Nuget package : Castle Windsor.

windsor castle

Après il faut créer les classes, interfaces et le IoC containter avec castle windsor.

using System;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using Castle.Windsor.Installer;

namespace WindsorEtLaReine
{
    class Program
    {
        static void Main(string[] args)
        {
            IWindsorContainer cont = new WindsorContainer();
            cont.Install(FromAssembly.This());
            cont.Register(Component.For<Vehicle>());
            //cont.Register(Component.For<IDriveable>().ImplementedBy<RollsRoyce>());
            cont.Register(Component.For<IDriveable>().ImplementedBy<HorseBuggy>());

            var conducteur = cont.Resolve<Vehicle>();
            conducteur.StartEngine();

            Console.ReadKey();
        }
    }

    public class Vehicle
    {
        private IDriveable o1;

        public Vehicle(IDriveable d1)
        {
            o1 = d1;
        }

        public void StartEngine()
        {
            o1.Drive();
        }
    }

    public interface IDriveable
    {
        void Drive();
    }

    public class RollsRoyce : IDriveable
    {
        public void Drive()
        {
            Console.WriteLine("Rolls Royce drive");
        }
    }

    public class HorseBuggy : IDriveable
    {
        public void Drive()
        {
            Console.WriteLine("Attention, coach on the road...");
        }
    }
}

Cet exemple montre la base d’utilisation d’un IoC container et le patron de conception Dependency Injection. J’espère que l’exemple leve un peu le voile sur le grand sujet Dependency Injection et Inversion of Control.

Intellisense pour AngularJS et JQuery avec Visual Studio Code

Pour utiliser intellisense dans le VS Code il est recommandé d’utiliser les fichiers TypeScript (.tsd) qui se trouvent dans un package npm. Voici le codage (Console + NodeJS) pour l’ajouter dans son projet.

npm install tsd -g
# cd to your project folder
tsd query -r -o -a install angular jquery

Events en C#

Les Events sont des actions comme key press, clic ou mouvement de souris, etc. ou des notifications créés par un système. En général, les applications doivent correspondre aux events quand ils occurrent, par exemple interrompre un logiciel. Principalement, les events sont utilisées pour la communication entre les procès.

Delegates et Events

La classe qui contient un évènement est utilisée pour publier un event. Cette classe s’appelle la classe publisher. Quelque autre classe qui accepte cet évènement est la calsse subscriber. Les events utilisent donc le model publisher-subscriber :
Un publisher, c’est un objet qui contient la définition d’un évènement et le delegate. L’objet d’une classe publisher invoque un event.
Un subscriber, c’est un objet qui accept un event et fourni un event handler. Le delegate dans la classe publisher invoque la méthode (event handler) d’une classe subscriber.

Voici un exemple :

namespace EventsExample
{
    class Program
    {
        static void Main(string[] args)
        {
            var button = new Button();
            button._clicked = A;
            button._clicked += B;
            button._clicked += C;
        }

        private static void C(object sender, EventArgs args)
        {
            throw new NotImplementedException();
        }

        private static void B(object sender, EventArgs args)
        {
            throw new NotImplementedException();
        }

        private static void A(object sender, EventArgs args)
        {
            var button = sender as Button;
            Console.WriteLine(button.Name);
        }
    }

    class ClickArgs : EventArgs
    {
        public int X { get; set; }
        public int Y { get; set; }

        public DateTime ClickTime { get; set; }

        public string Name { get; set; }
    }

    delegate void MyClickDelegate(object sender, ClickArgs args);

    class Button
    {
        public string Name { get; set; }      

        //public MyClickDelegate _clicked;

        public EventHandler<ClickArgs> _clicked;

        public void Click()
        {
            var args = new ClickArgs
            {
                X = 1,
                Y = 2,
                ClickTime = DateTime.Now
            };
            _clicked(this, args);
        }
    }
}

Les Collections originals en C#

Dans beaucoup des applications on veut grouper des objets de la même famille. En C# il y a deux façons de grouper les objets : Arrays et Collections.

En général, les Arrays sont très outil, quand on travaille avec des objets strongly-typed d’un nombre fixe (fixed number of strongly-typed objects).

En outre, les Collections fournissent une façon beaucoup plus flexible de travailler avec des groupes d’objets. Dans une collection, le groupe des objets peut facilement grandir et diminuer pour atteindre les besoins d’une application. En plus pour quelques collections on peut assigner une clé à n’importe quel objet, pour rapidement aller chercher un objet en utilisant cette clé.

Microsoft propose pas mal de classes de collection, the generic collections, qui se trouvent dans le namespace System.Collections.Generic

Les plus importants sont probablement :

Collection Ordering Access
Dictionary Unordered Via Key
SortedDictionary Sorted Via Key
SortedList Sorted Via Key
List User has precise control over element ordering Via Index
LinkedList User has precise control over element ordering No
HashSet Undordered Via Key
SortedSet Sorted Via Key
Stack LIFO Only Top
Queue FIFO Only Front

En plus il y a le vieux namespace System.Collections qui est considéré comme obsolète par Microsoft et beaucoup des développeurs. Dans cet namespace il y a ArrayList, Hashtable, Queue, SortedList, Stack.

LINQ en C#

Dans un dernier article on a regardé la fonctionnalité des expressions lambda, donc les fonctionnes anonymes. Autrefois j’ai écrit un article sur le sujet méthodes d’extension, qui va nous donner une base de savoir-faire en plus, dans cet article autour de LINQ.

MSDN propose également un bon réseau d’informations autour de LINQ.

Mais tout d’abord c’est quoi LINQ ?

LINQ c’est un acronyme pour Language Integrated Query. Simplifié on pourrait dire que LINQ est une bibliothèque de classes, qui nous donne des méthodes d’extension pour l’interface IEnumerable. Cette bibliothèque est donc disponible dans toutes les classes qui implémentent cette interface. Par exemple List<T>, Array, ObservableCollection<T>. Grâce à LINQ les queries sur les Collections en C# sont plus facile.

En gros, il y a 4 bibliothèques différentes :

  • LINQ to Object : query Arrays et Collections
  • LINQ to DataSet : query DataTables dans les DataSets
  • LINQ to XML : query XML Documents
  • LINQ to SQL : query SQL ServerPour obtenir plus d’information sur LINQ on peut également consulter MSDN.

LINQ propose deux notations différentes :

  • Query syntax
  • Method syntax

La query syntax ressemble beaucoup à un statement SQL. Un exemple se trouve dans le codage au dessous.

Maintenant regardons nous le method syntax d’une méthode LINQ très importante :

System.Linq.Enumerable.Where<TSource>
(this System.Collections.Generic.IEnumerable<TSource>, System.Func<TSource,bool>)

Ici on voit qu’il y a deux paramètres. Le premier paramètre comporte le mot clé this. Selon le mot clé this on voit facilement, qu’il s’agît d’une méthode d’extension, qui se réfère au type IEnumerable<T>. Le deuxième paramètre est une méthode (delegate) qui retourne une valeur boolean. Voici un exemple concret :

namespace LINQ
{
    class Program
    {
        static void Main(string[] args)
        {
            var animaux = new string[]{ "Caribou", "Ours", "Castor", "Baleine", "Beluga" };

            // Query syntax
            //var query = from a in animaux
            //            where a.StartsWith("B")
            //            select a;

            // Method syntax
            var query = animaux.Where(a => a.StartsWith("B"));

            foreach (var x in query)
            {
                Console.WriteLine(x);
            }

            Console.ReadKey();
        }
    }
}

Lambda en C#

Une expression Lambda c’est une fonctionne anonyme, qui peut être utilisé pour créer par exemple ses delegates. C’est-à-dire une fonctionne se transforme en une variable. En C# on utilise l’opérateur => pour indiquer une expression lambda.
Dans un dernier article autour de delegates on a vu qu’il y a Action<T> et Func<T>, ce qu’on peut utiliser pour enregistrer une méthode dans une variable, si la signature (la valeur retournée et la liste des paramètres) et la même chose que la signature du delegate.

namespace Lambda
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<int, int, double> mult = Multiply;

            var product = mult(3, 4);

            Console.WriteLine(product);

            Console.ReadKey();
        }

        private static double Multiply(int i, int j)
        {
            return i + j;
        }
    }
}

Si on ne veut qu’utiliser une méthode une seule fois par exemple, on peut utiliser une méthode anonyme :

namespace Lambda
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<int, int, double> mult = delegate(int i, int j)
            {
                return i + j;
            };

            Console.WriteLine(mult(3,4));

            Console.ReadKey();
        }
    }
}

On peut maintenant créer une expression lambda, on simplement raccourci le delegate en ne pas utilisant le mot clé delegate.

Func<int, int, double> mult = (int i, int j) =>
{
    return i + j;
};

Mais bien sûr on peut le raccourcir un peu plus :

Func<int, int, double> mult = (i, j) => i + j;

Delegates en C#

Dans le monde de la programmation objet orientée, on a souvent la réquisition d’exécuter un codage qui est défini dans une autre place, ou dont on ne connait pas exactement son contenu. Dans un tel cas, .NET offre la possibilité d’utiliser un Delegate.

C# Delegates peuvent être comparé avec des pointers vers une fonctionne dans le langage de programmation C ou C++. C’est-à-dire, un Delegate est une variable type de référence, qui comporte une référence à une méthode. Cette référence peut être changée pendant le runtime.

Normalement on utilise les Delegates pour implémenter des events ou des call-back methods.

namespace Delegates
{
    delegate void MyDelegate(string a); 

    class Program
    {
        static void Main(string[] args)
        {
            MyDelegate d = new MyDelegate(A);
        }

        static void A(string a)
        {
            // ... string action
        }
    }
}

Voici un exemple concrète pour un delegate simple :

namespace Delegates
{
    delegate void MyDelegate(string a); 

    class Program
    {
        static void Main(string[] args)
        {
            MyDelegate d = new MyDelegate(A);
            d("Caribou");

            Console.ReadKey();
        }

        static void A(string a)
        {
            Console.WriteLine(a);
        }
    }
}

Après on a assigné une méthode à un delegate, on peut facilement appeler cette méthode. Avec le delegate type de Action<T>, on peut appeler des méthodes sans return value et qui comportent jusqu’à 16 paramètres – no return value :

namespace Delegates
{
    class Program
    {
        static void Main(string[] args)
        {
            var d = new Action<int, string>(A);
            d(3, "Caribou");

            Console.ReadKey();
        }

        static void A(int a, string b)
        {
            Console.WriteLine("J'ai vu {0} {1}", a, b);
        }
    }
}

Si un return value est nécessaire, on utilise le delegate generic type de Func<T>, avec lequel on peut utiliser jusqu’à 16 paramètres plus un return value – return value:

namespace Delegates
{
    class Program
    {
        static void Main(string[] args)
        {
            var d = new Func<int, int, string>(A);
            Console.WriteLine(d(3,2));

            Console.ReadKey();
        }

        static string A(int a, int b)
        {
            string res = "J'ai vu " + (a + b) + " ours";

            return res;
        }
    }
}c

Une autre caractéristique vraiment utile d’un delegate c’est la possibilité d’en enchaîner. Donc, avec l’aide du operator += on peut montrer sur plusieurs méthodes à la fois.

delegate void MyDelegate(int a);

namespace Delegates
{
    class Program
    {
        static void Main(string[] args)
        {
            MyDelegate d1 = A;
            MyDelegate d2 = C;

            d1 += B;
            d1 += d2;

            d1(34);

            Console.ReadKey();
        }

        static void A(int a)
        {
            Console.WriteLine(a);
        }

        static void B(int b)
        {
            Console.WriteLine(b * 4);
        }

        static void C(int c)
        {
            Console.WriteLine(c * 6);
        }
    }
}

Les delegates sont souvent utilisés avec les events en C# et ils sont dérivés de la classe System.Delegate.