Tham số mặc định cho CancelToken


96

Tôi có một số mã không đồng bộ mà tôi muốn thêm CancellationTokenvào. Tuy nhiên, có nhiều triển khai mà điều này không cần thiết, vì vậy tôi muốn có một tham số mặc định - có lẽ CancellationToken.None. Tuy nhiên,

Task<x> DoStuff(...., CancellationToken ct = null)

hoa lợi

Không thể sử dụng giá trị kiểu '' làm tham số mặc định vì không có chuyển đổi tiêu chuẩn nào thành kiểu 'System.Threading.CancellationToken'

Task<x> DoStuff(...., CancellationToken ct = CancellationToken.None)

Giá trị tham số mặc định cho 'ct' phải là hằng số thời gian biên dịch

Có cách nào để có giá trị mặc định cho CancellationTokenkhông?

Câu trả lời:


151

Nó chỉ ra rằng những điều sau đây hoạt động:

Task<x> DoStuff(...., CancellationToken ct = default(CancellationToken))

theo tài liệu , được hiểu giống như CancellationToken.None:

Bạn cũng có thể sử dụng default(CancellationToken)câu lệnh C # để tạo mã thông báo hủy trống.


4
Đây chính xác là những gì mà khuôn khổ hiện đang làm trong nội bộ, nhưng tôi sẽ không làm điều đó trong mã của mình. Hãy nghĩ điều gì sẽ xảy ra với mã của bạn nếu Microsoft thay đổi cách triển khai của họ và CancellationToken.Nonetrở thành một thứ gì đó hơn thế nữa default(CancellationToken).
mũi,

10
@Noseratio Điều đó sẽ phá vỡ khả năng tương thích ngược theo một cách lớn, vì vậy tôi sẽ không mong đợi điều đó xảy ra. Và những gì khác sẽ default(CancellationToken)làm gì?
svick

3
@Noseratio: Bạn đang quá cứng nhắc. Rất có thể CancellationToken.Nonesẽ trở nên không được chấp nhận trên thực tế. Ngay cả Microsoft cũng đang sử dụng default(CancellationToken)thay thế. Ví dụ: xem các kết quả tìm kiếm này từ mã nguồn của Khung thực thể.
drowa

21
Từ Thuộc tính MSDN CancellationToken.None : "Bạn cũng có thể sử dụng câu lệnh C # mặc định (CancellationToken) để tạo mã thông báo hủy trống" . Không có gì là sai lầm cho đến khi phiên bản tương lai của C # chấp nhận nó làm tham số mặc định.
MuiBienCarlota,

5
Tương tự ở đây Để bù đắp cho hai kết hợp trung gian bị thiếu, các nhà phát triển có thể chuyển Không có hoặc một Can huỷToken mặc định cho tham số huỷToken và null cho tham số tiến trình.
Arek Bal

25

Có cách nào để có giá trị mặc định cho CancelToken không?

Thật không may, điều này là không thể, vì CancellationToken.Nonekhông phải là hằng số thời gian biên dịch, đây là yêu cầu đối với các giá trị mặc định trong các đối số tùy chọn.

Tuy nhiên, bạn có thể cung cấp hiệu ứng tương tự bằng cách tạo một phương thức quá tải thay vì cố gắng sử dụng các tham số mặc định:

Task<x> DoStuff(...., CancellationToken ct)
{
    //...
}

Task<x> DoStuff(....)
{
    return DoStuff(...., CancellationToken.None);
}

6
Đây là cách được khuyến nghị để xử lý điều này, như được giải thích trên tài liệu Mẫu không đồng bộ dựa trên tác vụ trên MSDN (cụ thể trong phần Chọn quá tải để cung cấp ).
Sam Harwell


5
Có chuyện gì CancellationToken cancellationToken = default(CancellationToken)vậy? Cũng được mô tả ở đây blog.msdn.microsoft.com/andrewarnottms/2014/03/19/…
Ray

20

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.Nonesẽ 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ó CancellationTokentham 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 nulllà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 ??.


11

Một tùy chọn khác là sử dụng một Nullable<CancellationToken>tham số, mặc định nó thành nullvà xử lý nó bên trong phương thức:

Task<x> DoStuff(...., CancellationToken? ct = null) {
    var token = ct ?? CancellationToken.None;
    ...
}

xuất sắc! cho đến nay đây là câu trả lời tốt nhất
John Henckel

4

Các phiên bản mới hơn của C # cho phép một cú pháp đơn giản hóa cho phiên bản mặc định (CancelToken). Ví dụ:

Task<x> DoStuff(...., CancellationToken ct = default)

-1

Câu trả lời của Tofutim là một cách, nhưng từ các bình luận, tôi thấy rằng mọi người có vấn đề với nó.

Trong trường hợp đó, tôi đã gợi ý rằng người ta có thể có một phương pháp như sau:

Task<x> DoStuff(...., CancellationToken ct)
{
} 

và quá tải nó như:

Task<x> DoStuff(....)
{
    return DoStuff(...., CancellationToken.None);
}

Điều này sẽ biên dịch, bởi vì giá trị của CancellationToken.Nonekhông được yêu cầu tại thời điểm biên dịch.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.