Fonctionnelle C # - ou en utilisant le retour d'action de
-
26-09-2019 - |
Question
Surfer sur le net pour une meilleure gestion des erreurs en C #, j'ai com à travers les éléments suivants aux stratégies de mise en œuvre. Le premier est naturel pour moi, alors que l'autre application je ne suis pas certain que ses avantages sont?
1)
static void Fault(Action protectedBlock, Action faultHandler)
{
try
{
protectedBlock();
}
catch
{
faultHandler();
throw;
}
}
2)
static Action Fault(Action protectedBlock, Action faultHandler)
{
return () =>
{
try
{
protectedBlock();
}
catch
{
faultHandler();
throw;
}
};
}
Est 2) la stratégie préférée lors de l'élaboration des fonctions d'ordre supérieur en C #?
Et, je me demande, si l'on approche est plus efficace que l'autre.
La solution
Le second cas est comme une usine d'action Faultable. Où vous passez un délégué de ce que vous voulez faire, protectedBlock
, et un délégué de ce qu'il faut faire lorsqu'un Exception
se produit, faultHandler
. Les actions sont retournées enveloppé dans une structure try / catch comme un Action
global. Mon problème avec ces deux méthodes est pas Exception
est en fait d'être pris alors qui va jamais attraper votre jet n'a pas d'informations sur lequel agir.
La différence d'exécution entre le 2 est quand ils procèdent à des exécutions. Le 1er sera exécuté quand elle est appelée. Le 2e exécutera chaque fois que le retour Action
est appelé. Je ne pense pas que la différence d'efficacité serait importante.
Autres conseils
(2) peut encore être composé, tandis que (1) seulement fonctionne. Mais ne sont exactement « fonctionnelle » comme Action
est pas une fonction (à comparer avec Func<A, R>
).
Donc, avec (2), vous pouvez faire:
Fault(someAction, Fault(firstTryFaultHandler, lastDitchFaultHandler))();
... et obtenir le comportement attendu. Cela ne fonctionne pas avec (1)
En C #, approche 2 peut être source de confusion. Un appelant peut utiliser "Fault (a, b);" attendant un et peut-être b à appeler. Au lieu de cela, un lambda est créé, retourné et mis au rebut. En d'autres mots rien est fait.
En ce qui concerne l'efficacité, l'approche 2 est un gaspillage de bits si la plupart de vos appels sont de la forme « défaut (a, b) (); », à savoir que vous invoquez le lambda immédiatement. Dans cette situation, vous n'avez pas besoin d'un lambda.
Pour ces raisons, je préfère l'approche 1. Si vous devez exécution defer, vous pouvez introduire un lambda explicitement "() => Défaut (a, b)".