Похоже, что намерением ОП было найти хороший образец для решения своей проблемы и решения текущей проблемы, с которой он боролся в тот момент.
ОП: «Я мог бы заключить каждое вычисление во вспомогательный метод, который возвращает ноль в случае ошибки, а затем просто использовать ??
оператор, но есть ли способ сделать это в более общем плане (т.е. без необходимости писать вспомогательный метод для каждого метода, который я хочу use)? Я думал о написании статического метода с использованием универсальных шаблонов, которые обертывают любой заданный метод в try / catch и возвращают null в случае неудачи, но я не уверен, как бы я поступил с этим. Есть идеи? "
Я видел много хороших шаблонов, которые избегают вложенных блоков try catch , размещенных в этом фиде, но не нашел решения проблемы, о которой говорилось выше. Итак, вот решение:
Как упоминалось выше, он хотел создать объект-оболочку, который возвращается null
в случае сбоя . Я бы назвал это модулем ( безопасный модуль ).
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;
Но что, если вы хотите создать безопасный модуль для результата ссылочного типа, возвращаемого функциями / методами 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}";
}
Итак, вы могли заметить, что нет необходимости «писать вспомогательный метод для каждого метода, который вы хотите использовать» .
Эти два типа стручков (для ValueTypeResult
s- и ReferenceTypeResult
с) являются достаточно .
Вот код SafePod
. Но это не контейнер. Вместо этого он создает безопасную в отношении исключений оболочку делегата для ValueTypeResult
s и 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;
}
}
Вот как вы можете использовать оператор ??
объединения с нулевым значением в сочетании с мощью первоклассных гражданских сущностей delegate
.