2009-12-29 2 views
0

Tenir compte de l'extrait de code suivant:Runtime chèque pour un délégué Func

class Test 
{ 
    public int Length{ get; set; } 
    public Func<List<int>, double> Calculate { get; set; } 
    public void DoStuff(List<int> list) 
    { 
     // ... do some processing here ... 
     double ans = Calculate(list); 
     // ... do some more stuff ...... 
    } 
} 

Maintenant, je réalise que le délégué Func typique anonyme qui sera attaché à la propriété Calculer, aurait quelque chose à voir avec le Propriété Length de la classe Test et longueur de la liste transmise au délégué. Pour une certaine relation entre ces deux longueurs (par exemple, cette longueur < liste.Count), je devrais être en mesure de lancer une exception. Mais, cela doit arriver à l'exécution, et je n'aurais aucun contrôle sur ce que les utilisateurs de cette classe ajouteraient en tant que délégué dans la propriété Calculate.

Comment faire? Puis-je faire quelque chose dans la méthode set de la propriété Calculate? Comment vérifier au moment de l'exécution si certaines conditions impliquant la propriété Length de la classe Test et la longueur (count) de l'objet liste transmis au délégué sont satisfaites?

Je considérerais également les changements de conception de la classe Test pour accomplir mon objectif (de vérification de l'exécution), mais un moyen pour les utilisateurs d'attacher un délégué Func et accomplir encore ce serait soigné.
Merci. Ajoutez vos propres vérifications avant d'appeler le délégué fourni.

Répondre

2

De cette façon, vous pouvez vérifier que toutes les exigences sont remplies avant d'invoquer et que la vérification est effectuée en un seul endroit (au lieu d'être dupliqué dans chaque implémentation).

public void DoStuff(List<int> list) 
{ 
    CheckPreconditions(list); 
    double ans = Calculate(list);   
} 

private void CheckPreconditions(List<int> list) 
{ 
    if(list == null) 
     // throw ... 

    if(list.Length == 0) 
     // throw ... 

    if(Length < list.Count) 
     throw ArgumentException("list", 
      "list must have blah blah blah to satisfy requirements"); 
} 

Ceci est similaire à l'exception template method pattern au lieu d'utiliser l'héritage, vous déléguer à une fonction fournie par l'utilisateur :)

En outre, si vous faites Calculer un champ au lieu d'une propriété publique, vous peut forcer l'exécution à l'aide de la méthode DoStuff, de sorte que les vérifications seront toujours effectuées.

Quelque chose comme:

class Test 
{ 
    public int Length{ get; set; } 
    private Func<List<int>, double> m_calculate; 

    // Inject into ctor 
    public Test(Func<List<int>, double> calculate) 
    { 
     if(calculate == null) throw new ArgumentNullException("calculate"); 

     m_calculate = calculate; 
    } 

    // all access to Calculate is now through this method 
    public void DoStuff(List<int> list) 
    { 
     CheckPreconditions(list); 
     double ans = m_calculate(list);   
    } 
} 

Ce serait un bon ajustement si calculate est ne modifions une fois.

+0

Excellent. J'ai pensé à l'exécution des vérifications avant d'appeler le délégué Func, mais j'ai manqué d'en faire un champ privé afin que les vérifications puissent toujours avoir lieu. Merci beaucoup. –