Mitsu Furuta

Another .Text Powered Blog

  Home :: Syndication  :: Login
  51 Posts :: 0 Stories :: 0 Comments :: 5524 Trackbacks

Archives

Categories

Centres de développement

Les mercredis du développement

Bonjour à tous,

Le mercredi du développement sur C# 2.0 s'est bien déroulé mercredi dernier et les webcasts sont en cours de mise en ligne (ce qui devrait prendre une dizaine de jours car nous avons quelques problèmes techniques).
Pour nous faire pardonner et vous faire patienter, je vous propose deux petits extraits dans ce post.

Bonne lecture et donc à très bientôt pour les webcasts dont j'annoncerai la disponibilité sur ce même blog.

Mitsu

1- Factoriser des instructions de bloc.

L'idée est la suivante, imaginons que nous voulions factoriser une gestion d'erreur pour toute notre application avec un traitement d'erreur centralisé. Dans bon nombre de cas existants (comme les apis win32), un modèle classique consiste à implémenter des méthodes qui renvoient un entier. Il devient alors assez simple de créer une méthode ShowError(int errorCode) qui centralise la gestion d'erreur. Ce modèle impose la convention qui consiste à renvoyer un entier et ne factorise pas le try...catch que nous devons implémenter dans toutes les méthodes.

private int AddCustomer(string param)
{
  try
  {
    int i = Convert
.ToInt32(param);
  }
  catch
  {
    return
1;
  }
  return
0;
}

private void ShowError(int value)
{
 
if
(value != 0)
   
switch
(value)
   
{
     
case
1:
     
case
2:
     
default
:
       
MessageBox.Show("Une erreur s'est produite: n°"
+ value.ToString());
       
break
;
    }
}

L'appel ressemble alors à:

ShowError(AddCustomer("blabla"));

L'idée en C# 2.0 est d'utiliser les méthodes anonymes pour retarder l'exécution du code critique afin de prendre le temps d'encadrer l'appel par un bloc try...catch. Nous aurons besoin d'un délégué le plus simple possible afin d'être générique. Le code des méthodes anonymes ayant accès aux membres accessibles depuis la méthode hôte, nous de déclarerons aucun paramètre.

public delegate void SimpleDelegate();

Nous pouvons alors implémenter une unique méthode de gestion des exceptions incluant le bloc try...catch.

private void SafeCall(SimpleDelegate d)
{
 
try
 
{
   
if (d != null
)
      d();
  }
 
catch (Exception
e)
  {
   
MessageBox.Show("Une erreur s'est produite:"
+ e.Message);
  }
}

L'appel devient alors très simple:

string s = "blabla";
SafeCall
(
delegate
{
 
int i = Convert
.ToInt32(s);
});

Nous pouvons également imaginer utiliser ce même pattern pour centraliser les transactions.

InTransaction(delegate
{
  AddCustomer();
});

1- Enumerer des énumérations ..?!?!

Les types enum de .Net permettent de stocker un ensemble de valeurs en utilisant la vue binaire de l'entier sousjacent de l'énumération.
Ce pattern est très connu et est largement utilisé à la fois dans le framework .Net et dans l'api win32.

Exemple:

[Flags]
public enum Day { None = 0, Lundi = 1, Mardi = 2, Mercredi = 4, Jeudi = 8, Vendredi = 16, Samedi = 32, Dimanche = 64 };

Récupérer la liste des valeurs stockées dans l'énuméré demande donc un parcours binaire de l'ensemble des bits en utilisant un 'et' binaire (&) pour tester les différentes valeurs.
L'idée est alors d'accèder à cette liste de valeurs via une énumération (IEnumerable). Nous utiliserons les itérations de C# 2.0 pour faciliter cette implémentation (yield return).

private IEnumerable<T> GetEnumeration<T>(T values) where T : struct
{
 
if (!typeof(T).IsSubclassOf(typeof(Enum
)))
   
throw new Exception("n'est pas un Enum"
);
 
int[] allValues = (int[])Enum.GetValues(typeof
(T));
 
int intValues = Convert
.ToInt32(values);
 
foreach (int i in
allValues)
  {
   
if
((i & intValues) != 0)
     
yield return (T)Enum.ToObject(typeof
(T), i);
 
}
}

L'appel devient alors:

Day d = Day.Samedi | Day.Jeudi;
foreach (Day d2 in GetEnumeration<Day>(d))...

Essayons d'implémenter cette fonctionnalité de façon plus intégré. Nous pouvons utiliser le pattern des nullables.

public struct MyEnum<T> : IEnumerable<T> where T : struct
{
 
public
MyEnum(T value)
  {
    _value = value;
  }
 
private
T _value;
 
public static implicit operator T(MyEnum
<T> e)
  {
   
return
e._value;
  }
 
public static implicit operator MyEnum
<T>(T e)
  {
   
return new MyEnum
<T>(e);
  }
 
public static MyEnum<T> FromEnumerable(IEnumerable
<T> e)
  {
   
int
value = 0;
   
foreach (T t in
e)
    {
      value |=
Convert
.ToInt32(t);
    }
   
return (T)Enum.ToObject(typeof
(T), value);
  }

  #region IEnumerable<T> Members
 
IEnumerator<T> IEnumerable
<T>.GetEnumerator()
  {
   
if (!typeof(T).IsSubclassOf(typeof(Enum
)))
     
throw new Exception("n'est pas un enum"
);
   
int[] allValues = (int[])Enum.GetValues(typeof
(T));
   
int intValues = Convert
.ToInt32(_value);
   
foreach (int i in
allValues)
    {
     
if
((i & intValues) != 0)
       
yield return (T)Enum.ToObject(typeof
(T), i);
    }
  }
 
#endregion

  #region IEnumerable Members
 
IEnumerator IEnumerable
.GetEnumerator()
  {
   
return (this as IEnumerable<T>).GetEnumerator() as IEnumerator
;
  }
 
#endregion

  public override string ToString()
  {
   
return
_value.ToString();
  }
}

L'utilisation est alors fortement simplifiée:

MyEnum<Day> d = Day.Samedi | Day.Jeudi;

foreach (Day d2 in d) ...

Day d3 = d;

L'énumération ainsi crée profitera des fonctions ensemblistes de C# 3.0:

d.Intersect(d2);

 

posted on samedi 30 septembre 2006 21:41

Feedback

# Linq to bits ! 08/10/2006 20:24 Mitsu Furuta