Enrichissement d’un handler à l’aide des closures

Closures

Samedi soir, bonsoir !

France vs. Roumanie. D’un coté « Allez la France », de l’autre « Hai Romania », qui va gagner ?
Le meilleur j’espère, en tout cas passons, nous avons du code sur la planche.

Tout d’abord, mes plus fidèles lecteurs (y’en à t’il ?) ont dû remarquer que la cadence de mes articles a ralenti.
Pourquoi ? La raison est simple, mon stage de fin d’année touche à sa fin et le projet que j’ai pu mener pendant ses 3 mois commence à se concrétiser donc mon temps libre est considérablement réduit. Le tutoriel sur le développement d’une petite application pour Windows Mobile est toujours sur le feu, ne vous inquiétez pas cela arrive.

Ce soir, j’ai décidé d’écrire un petit article pour vous faire part d’une astuce très pratique qui semblera logique pour les dotneteurs les plus avancés, mais filera un bon coup de main au débutant qui débute :D .

Premièrement, posons le contexte, nous allons prendre comme exemple une classe provenant des librairies d’interopérabilité avec Excel. Dans ce domaine, on est souvent amené à utiliser l’interface Workbook pour manipuler un classeur Excel. Imaginez que vous devez intercepter l’ouverture de vos classeurs.

Vous avez deux choix possibles, soit vous abonnez à Microsoft.Office.Interop.Excel.Application.WorkbookOpen qui vous appellera à chaque ouverture de classeurs, soit vous abonnez à Workbook.Open pour chaque classeur.

Le premier cas a comme avantage de définir un seul abonnement global, mais comme inconvénient la nécessité de filtrer les classeurs qui nous intéressent. Le deuxième est à première vue très lourd à gérer, mais avec la petite astuce que je vais vous montrer, ce choix s’avère le plus efficace et le plus rapide à mettre en place.
Vous ne me croyez pas ? Regardez.

Imaginez qu’on a 4 classeurs à gérer, le débutant fera naïvement ceci :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
static void Main(string[] args)
{
    Workbook workbook1 = null;
    Workbook workbook2 = null;
    Workbook workbook3 = null; 
    Workbook workbook4 = null;
 
    workbook1.Open += OnOpen1;
    workbook2.Open += OnOpen2;
    workbook3.Open += OnOpen3;
    workbook4.Open += OnOpen4;
}
 
private static void OnOpen1()
{
    throw new NotImplementedException();
}
 
private static void OnOpen2()
{
    throw new NotImplementedException();
}
 
private static void OnOpen3()
{
    throw new NotImplementedException();
}
 
private static void OnOpen4()
{
    throw new NotImplementedException();
}

Aïe mes yeux… Alors, imaginons si nous lui avions donné 40 classeurs à gérer :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static void Main(string[] args)
{
    List<Workbook> workbooks = new List<Workbook>();
 
    foreach (Workbook workbook in workbooks)
    {
        workbook.Open += OnOpen;
    }
}
 
private static void OnOpen()
{
    //Mon classeur est ouvert ! Youpi mais lequel ?
}

Ah là c’est mieux, mais comme je le fais remarquer dans mon commentaire avec cette technique il est impossible de déterminer quel classeur a été ouvert.

Bon, mais en fait si le premier choix était le seul valable ? Mais non ! Regardez, on va jouer avec les closures :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static void Main(string[] args)
{
    List<Workbook> workbooks = new List<Workbook>();
 
    foreach (Workbook workbook in workbooks)
    {
        Workbook localWorkbook = workbook;
        workbook.Open += () => OnOpen(localWorkbook);
    }
}
 
private static void OnOpen(Workbook workbook)
{
    //Ah j'ai réussi !
}

Vous voyez que vous pouvez me croire, on a enrichi notre handler avec une référence sur le classeur qui a été ouvert. Corsons un tout petit peu les choses, imaginez que l’on veut se désinscrire de cet évènement une fois le classeur ouvert.

La première chose à quel on pense c’est de se désinscrire en essayant de retrouver notre delegate grâce à la reflection, mais en fait voici la petite astuce :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static void Main(string[] args)
{
    List<Workbook> workbooks = new List<Workbook>();
 
    foreach (Workbook workbook in workbooks)
    {
        WorkbookEvents_OpenEventHandler handler = null;
        Workbook localWorkbook = workbook;
        handler = delegate
        {
            OnOpen(localWorkbook);
            localWorkbook.Open -= handler;
        };
 
        workbook.Open += handler;
    }
}
 
private static void OnOpen(Workbook workbook)
{
    //Et voilà !
}

Voilà, la boucle est bouclée. J’espère que ce petit article vous a appris des choses et surtout démontré la puissance des closures. N’hésitez pas à laisser un commentaire sur votre appréciation.

À bientôt guys.

Publié dans .NET, Développement, Office.

Classé dans , , , .


0 réponses

Suivez la conversation, abonnez-vous au flux RSS des commentaires..



Un peu de HTML est permis

ou héberger un rétrolien.