Có vẻ như ý định của OP là tìm ra một mô hình tốt để giải quyết vấn đề của anh ấy và giải quyết vấn đề hiện tại mà anh ấy đang phải vật lộn vào thời điểm đó.
OP: "Tôi có thể gói mỗi phép tính trong một phương thức trợ giúp trả về null khi không thành công, và sau đó chỉ cần sử dụng ??
toán tử, nhưng có cách nào để thực hiện điều này tổng quát hơn không (nghĩa là không cần phải viết phương thức trợ giúp cho mỗi phương thức mà tôi muốn use)? Tôi đã nghĩ về việc viết một phương thức tĩnh bằng cách sử dụng generic bao bọc bất kỳ phương thức nào đã cho trong một lần thử / bắt và trả về null khi thất bại, nhưng tôi không chắc mình sẽ làm như thế nào về điều này. Có ý kiến gì không? "
Tôi đã thấy rất nhiều mẫu hay để tránh các khối try catch lồng nhau , được đăng trong nguồn cấp dữ liệu này, nhưng không tìm thấy giải pháp cho vấn đề được trích dẫn ở trên. Vì vậy, đây là giải pháp:
Như OP đã đề cập ở trên, anh ấy muốn tạo một đối tượng wrapper sẽ trả về null
khi bị lỗi . Tôi sẽ gọi nó là một pod ( Vỏ an toàn cho ngoại lệ ).
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;
Nhưng điều gì sẽ xảy ra nếu bạn muốn tạo một nhóm an toàn cho kết quả Kiểu Tham chiếu được trả về bởi các hàm / phương thức 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}";
}
Vì vậy, bạn có thể nhận thấy rằng không cần "viết phương thức trợ giúp cho mỗi phương thức bạn muốn sử dụng" .
Các hai loại vỏ (ví ValueTypeResult
s và ReferenceTypeResult
s) là đủ .
Đây là mã của SafePod
. Tuy nhiên, nó không phải là một thùng chứa. Thay vào đó, nó tạo một trình bao bọc đại biểu an toàn ngoại lệ cho cả ValueTypeResult
s và 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;
}
}
Đó là cách bạn có thể tận dụng toán tử ??
kết hợp null kết hợp với sức mạnh của ( các) thực thể công dân hạng nhấtdelegate
.