Dưới đây là một số giải pháp, theo thứ tự độ tốt chung giảm dần:
1. Sử dụng default(CancellationToken)
làm giá trị mặc định:
Task DoAsync(CancellationToken ct = default(CancellationToken)) { … }
Về mặt ngữ nghĩa, CancellationToken.None
sẽ là ứng cử viên lý tưởng cho giá trị mặc định, nhưng không thể được sử dụng như vậy vì nó không phải là hằng số thời gian biên dịch. default(CancellationToken)
là điều tốt nhất tiếp theo vì nó là một hằng số thời gian biên dịch và được ghi lại chính thức là tương đương vớiCancellationToken.None
.
2. Cung cấp quá tải phương thức mà không có CancellationToken
tham số:
Hoặc, nếu bạn thích quá tải phương thức hơn các tham số tùy chọn (xem phần này và câu hỏi này về chủ đề đó):
Task DoAsync(CancellationToken ct) { … } // actual method always requires a token
Task DoAsync() => DoAsync(CancellationToken.None); // overload producing a default token
Đối với các phương pháp giao diện, có thể đạt được điều tương tự bằng cách sử dụng các phương pháp mở rộng:
interface IFoo
{
Task DoAsync(CancellationToken ct);
}
static class Foo
{
public static Task DoAsync(this IFoo foo) => foo.DoAsync(CancellationToken.None);
}
Điều này dẫn đến một giao diện mỏng hơn và ngăn người triển khai viết quá tải phương thức chuyển tiếp một cách rõ ràng.
3. Làm cho tham số là vô hiệu và sử dụng null
làm giá trị mặc định:
Task DoAsync(…, CancellationToken? ct = null)
{
… ct ?? CancellationToken.None …
}
Tôi thích giải pháp này nhất vì các kiểu nullable đi kèm với chi phí thời gian chạy nhỏ và các tham chiếu đến mã thông báo hủy trở nên dài dòng hơn vì toán tử liên kết null ??
.
CancellationToken.None
trở thành một thứ gì đó hơn thế nữadefault(CancellationToken)
.