พารามิเตอร์ดีฟอลต์สำหรับ Can CancelToken


98

ฉันมีรหัส async บางอย่างที่ผมอยากจะเพิ่มCancellationTokenไป แต่มีการใช้งานจำนวนมากที่นี้ไม่จำเป็นต้องดังนั้นผมจึงอยากมีพารามิเตอร์เริ่มต้น - CancellationToken.Noneบางที อย่างไรก็ตาม

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

ผลตอบแทน

ไม่สามารถใช้ค่าประเภท '' เป็นพารามิเตอร์เริ่มต้นได้เนื่องจากไม่มีการแปลงมาตรฐานให้พิมพ์ 'System.Threading.CancellationToken'

และ

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

ค่าพารามิเตอร์เริ่มต้นสำหรับ 'ct' ต้องเป็นค่าคงที่เวลาคอมไพล์

มีวิธีใดบ้างที่จะมีค่าเริ่มต้นสำหรับCancellationToken?

คำตอบ:


155

ปรากฎว่าการทำงานต่อไปนี้:

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

...หรือ:

Task<x> DoStuff(...., CancellationToken ct = default) // C# 7.1 and later

ซึ่งตามเอกสารนี้ตีความเช่นเดียวกับCancellationToken.None:

คุณยังสามารถใช้default(CancellationToken)คำสั่งC # เพื่อสร้างโทเค็นการยกเลิกที่ว่างเปล่า


4
นี่คือสิ่งที่เฟรมเวิร์กทำภายในในปัจจุบันแต่ฉันจะไม่ทำในโค้ดของฉัน คิดว่าสิ่งที่เกิดขึ้นกับรหัสของคุณถ้าไมโครซอฟท์เปลี่ยนการดำเนินงานของพวกเขาและจะกลายเป็นสิ่งที่มากกว่าCancellationToken.None default(CancellationToken)
อัตราส่วนจมูก

10
@Noseratio นั่นจะทำลายความเข้ากันได้แบบย้อนกลับอย่างมากดังนั้นฉันไม่คาดหวังว่าจะเกิดขึ้น แล้วจะdefault(CancellationToken)ทำอะไรอีก?
svick

4
@Noseratio: คุณเข้มงวดเกินไป มีโอกาสที่CancellationToken.Noneจะเลิกใช้งานโดยพฤตินัย แม้แต่ไมโครซอฟต์ก็ใช้default(CancellationToken)แทน ตัวอย่างเช่นดูผลการค้นหาเหล่านี้จากซอร์สโค้ดของ Entity Framework
drowa

21
จาก MSDN CancellationToken.None ทรัพย์สิน : "นอกจากนี้คุณยังสามารถใช้ C # เริ่มต้น (CancellationToken) คำสั่งเพื่อสร้างโทเค็นการยกเลิกว่างเปล่า" ไม่มีข้อผิดพลาดจนกว่า C # เวอร์ชันอนาคตจะยอมรับเป็นพารามิเตอร์เริ่มต้น
MuiBienCarlota

5
เหมือนกันที่นี่ เพื่อชดเชยชุดค่าผสมระดับกลางที่ขาดหายไปสองชุดนักพัฒนาอาจส่ง None หรือ Can CancelToken เริ่มต้นสำหรับพารามิเตอร์ CancelToken และ null สำหรับพารามิเตอร์ความคืบหน้า
Arek Bal

25

มีวิธีใดบ้างที่จะมีค่าเริ่มต้นสำหรับ Can CancelToken

น่าเสียดายที่สิ่งนี้เป็นไปไม่ได้เนื่องจากCancellationToken.Noneไม่ใช่ค่าคงที่เวลาคอมไพล์ซึ่งเป็นข้อกำหนดสำหรับค่าเริ่มต้นในอาร์กิวเมนต์ที่เป็นทางเลือก

อย่างไรก็ตามคุณสามารถให้เอฟเฟกต์เดียวกันได้โดยสร้างวิธีที่มากเกินไปแทนที่จะพยายามใช้พารามิเตอร์เริ่มต้น:

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

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

6
นี่เป็นวิธีที่แนะนำในการจัดการสิ่งนี้ตามที่อธิบายไว้ในเอกสารเกี่ยวกับรูปแบบอะซิงโครนัสตามงานบน MSDN (เฉพาะในส่วนการเลือกโอเวอร์โหลดที่จะให้ )
Sam Harwell


5
เกิดอะไรขึ้นCancellationToken cancellationToken = default(CancellationToken)? อธิบายไว้ที่นี่blogs.msdn.microsoft.com/andrewarnottms/2014/03/19/…
Ray

20

ต่อไปนี้เป็นวิธีแก้ปัญหาหลายประการตามลำดับจากมากไปหาน้อย:

1. ใช้default(CancellationToken)เป็นค่าเริ่มต้น:

Task DoAsync(CancellationToken ct = default(CancellationToken)) { … }

ตามความหมายCancellationToken.Noneจะเป็นตัวเลือกที่เหมาะสำหรับค่าเริ่มต้น แต่ไม่สามารถใช้เช่นนี้ได้เนื่องจากไม่ใช่ค่าคงที่เวลาคอมไพล์ default(CancellationToken)เป็นสิ่งที่ดีที่สุดถัดไปเนื่องจากเป็นค่าคงที่เวลาคอมไพล์และบันทึกอย่างเป็นทางการว่าเทียบเท่ากับCancellationToken.None .

2. ระบุวิธีการโอเวอร์โหลดโดยไม่มีCancellationTokenพารามิเตอร์:

หรือหากคุณต้องการให้เมธอดโอเวอร์โหลดพารามิเตอร์เสริม (ดูสิ่งนี้และคำถามนี้ในหัวข้อนั้น):

Task DoAsync(CancellationToken ct) { … } // actual method always requires a token
Task DoAsync() => DoAsync(CancellationToken.None); // overload producing a default token

สำหรับวิธีการเชื่อมต่อสามารถทำได้โดยใช้วิธีการขยาย:

interface IFoo
{
    Task DoAsync(CancellationToken ct);
}

static class Foo
{
    public static Task DoAsync(this IFoo foo) => foo.DoAsync(CancellationToken.None);
}

ส่งผลให้อินเทอร์เฟซที่บางลงและช่วยลดการใช้งานจากการเขียนวิธีการส่งต่อที่มากเกินไปอย่างชัดเจน

3. ทำให้พารามิเตอร์เป็นโมฆะและใช้nullเป็นค่าเริ่มต้น:

Task DoAsync(…, CancellationToken? ct = null)
{
    … ct ?? CancellationToken.None …
}

ผมชอบวิธีนี้น้อยเพราะประเภท nullable ??มาพร้อมกับค่าใช้จ่ายรันไทม์ขนาดเล็กและการอ้างอิงถึงการยกเลิกโทเค็นมากขึ้นอย่างละเอียดเพราะผู้ประกอบการ


11

อีกทางเลือกหนึ่งคือการใช้Nullable<CancellationToken>พารามิเตอร์เริ่มต้นเป็นnullและจัดการกับมันภายในวิธีการ:

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

แจ่ม! นี่คือคำตอบที่ดีที่สุด
John Henckel

6

C # เวอร์ชันใหม่กว่าอนุญาตให้ใช้ไวยากรณ์ที่เรียบง่ายสำหรับเวอร์ชันเริ่มต้น (Can CancelToken) เช่น:

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

-1

คำตอบของ Tofutimเป็นวิธีหนึ่ง แต่จากความคิดเห็นฉันเห็นว่าผู้คนมีปัญหากับมัน

ในกรณีนั้นฉันแนะนำว่าเราสามารถมีวิธีการดังต่อไปนี้:

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

และโอเวอร์โหลดเป็น:

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

คอมไพล์นี้เนื่องจากCancellationToken.Noneไม่จำเป็นต้องใช้ค่าของในเวลาคอมไพล์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.