Il semble que l'intention du PO était de trouver un bon modèle pour résoudre son problème et résoudre le problème actuel avec lequel il luttait à ce moment-là.
OP: "Je pourrais encapsuler chaque calcul dans une méthode d'assistance qui renvoie null en cas d'échec, puis utiliser simplement l' ??
opérateur, mais y a-t-il un moyen de le faire plus généralement (c'est-à-dire sans avoir à écrire une méthode d'assistance pour chaque méthode que je veux use)? J'ai pensé à écrire une méthode statique utilisant des génériques qui encapsule une méthode donnée dans un try / catch et renvoie null en cas d'échec, mais je ne suis pas sûr de la manière dont je procéderais. Des idées? "
J'ai vu beaucoup de bons modèles qui évitent les blocs try catch imbriqués , publiés dans ce flux, mais n'ai pas trouvé de solution au problème cité ci-dessus. Alors, voici la solution:
Comme OP mentionné ci-dessus, il voulait créer un objet wrapper qui retourne null
en cas d'échec . Je l'appellerais un pod ( pod sans danger pour les exceptions ).
public static void Run()
{
// The general case
// var safePod1 = SafePod.CreateForValueTypeResult(() => CalcX(5, "abc", obj));
// var safePod2 = SafePod.CreateForValueTypeResult(() => CalcY("abc", obj));
// var safePod3 = SafePod.CreateForValueTypeResult(() => CalcZ());
// If you have parameterless functions/methods, you could simplify it to:
var safePod1 = SafePod.CreateForValueTypeResult(Calc1);
var safePod2 = SafePod.CreateForValueTypeResult(Calc2);
var safePod3 = SafePod.CreateForValueTypeResult(Calc3);
var w = safePod1() ??
safePod2() ??
safePod3() ??
throw new NoCalcsWorkedException(); // I've tested it on C# 7.2
Console.Out.WriteLine($"result = {w}"); // w = 2.000001
}
private static double Calc1() => throw new Exception("Intentionally thrown exception");
private static double Calc2() => 2.000001;
private static double Calc3() => 3.000001;
Mais que faire si vous souhaitez créer un pod sécurisé pour un résultat de type de référence retourné par les fonctions / méthodes CalcN ().
public static void Run()
{
var safePod1 = SafePod.CreateForReferenceTypeResult(Calc1);
var safePod2 = SafePod.CreateForReferenceTypeResult(Calc2);
var safePod3 = SafePod.CreateForReferenceTypeResult(Calc3);
User w = safePod1() ?? safePod2() ?? safePod3();
if (w == null) throw new NoCalcsWorkedException();
Console.Out.WriteLine($"The user object is {{{w}}}"); // The user object is {Name: Mike}
}
private static User Calc1() => throw new Exception("Intentionally thrown exception");
private static User Calc2() => new User { Name = "Mike" };
private static User Calc3() => new User { Name = "Alex" };
class User
{
public string Name { get; set; }
public override string ToString() => $"{nameof(Name)}: {Name}";
}
Ainsi, vous remarquerez peut-être qu'il n'est pas nécessaire "d'écrire une méthode d'assistance pour chaque méthode que vous souhaitez utiliser" .
Les deux types de pods (pour ValueTypeResult
s et ReferenceTypeResult
s) suffisent .
Voici le code de SafePod
. Ce n'est cependant pas un conteneur. Au lieu de cela, il crée un wrapper de délégué sécurisé pour les exceptions pour ValueTypeResult
s et ReferenceTypeResult
s.
public static class SafePod
{
public static Func<TResult?> CreateForValueTypeResult<TResult>(Func<TResult> jobUnit) where TResult : struct
{
Func<TResult?> wrapperFunc = () =>
{
try { return jobUnit.Invoke(); } catch { return null; }
};
return wrapperFunc;
}
public static Func<TResult> CreateForReferenceTypeResult<TResult>(Func<TResult> jobUnit) where TResult : class
{
Func<TResult> wrapperFunc = () =>
{
try { return jobUnit.Invoke(); } catch { return null; }
};
return wrapperFunc;
}
}
C'est ainsi que vous pouvez tirer parti de l'opérateur de fusion nul ??
combiné à la puissance d' entités citoyennes de premier ordredelegate
.