Task <int> กลายเป็น int ได้อย่างไร?


116

เรามีวิธีนี้:

async Task<int> AccessTheWebAsync()
{ 
    HttpClient client = new HttpClient();

   Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

   // You can do work here that doesn't rely on the string from GetStringAsync.
   DoIndependentWork();

   string urlContents = await getStringTask;
   //The thing is that this returns an int to a method that has a return type of Task<int>
   return urlContents.Length;
}

การแปลงโดยปริยายเกิดขึ้นระหว่างTask<int>และint? ถ้าไม่เช่นนั้นจะเกิดอะไรขึ้น? นำไปใช้งานอย่างไร?


1
อ่านต่อไป ฉันถือว่าคอมไพเลอร์ดูแลสิ่งนั้นตามasyncคีย์เวิร์ด
D Stanley

1
@Freeman ดูคำอธิบายที่ยอดเยี่ยมนี้: stackoverflow.com/a/4047607/280758
qehgt

คำตอบ:


171

การแปลงโดยปริยายเกิดขึ้นระหว่าง Task <> และ int หรือไม่

Nope นี่เป็นเพียงส่วนหนึ่งของวิธีการasync/ awaitทำงาน

วิธีการใด ๆ ที่ประกาศว่าasyncต้องมีผลตอบแทนประเภท:

  • void (หลีกเลี่ยงถ้าเป็นไปได้)
  • Task (ไม่มีผลลัพธ์นอกเหนือจากการแจ้งความสำเร็จ / ล้มเหลว)
  • Task<T>(สำหรับผลลัพธ์เชิงตรรกะของประเภทTในลักษณะไม่ซิงค์)

คอมไพเลอร์ทำการห่อที่เหมาะสมทั้งหมด ประเด็นก็คือคุณกำลังส่งคืนแบบอะซิงโครนัสurlContents.Length - คุณไม่สามารถทำให้เมธอดกลับมาintได้เนื่องจากเมธอดจริงจะส่งคืนเมื่อมันไปถึงawaitนิพจน์แรกที่ยังไม่เสร็จ ดังนั้นแทนที่จะส่งกลับTask<int>ซึ่งจะเสร็จสมบูรณ์เมื่อวิธีการ async เสร็จสิ้น

โปรดทราบว่าawaitสิ่งที่ตรงกันข้าม - มันคลาย a Task<T>เป็นTค่าซึ่งเป็นวิธีการทำงานของบรรทัดนี้:

string urlContents = await getStringTask;

... แต่แน่นอนว่ามันจะแกะมันออกมาแบบอะซิงโครนัสในขณะที่การใช้งานResultจะบล็อกจนกว่างานจะเสร็จสิ้น ( awaitสามารถแกะประเภทอื่น ๆ ที่ใช้รูปแบบที่รอคอยได้ แต่Task<T>เป็นรูปแบบที่คุณน่าจะใช้บ่อยที่สุด)

การห่อ / แกะแบบคู่นี้เป็นสิ่งที่ช่วยให้ async สามารถประกอบได้ ตัวอย่างเช่นฉันสามารถเขียนวิธี async อื่นที่เรียกคุณและเพิ่มผลลัพธ์เป็นสองเท่า:

public async Task<int> AccessTheWebAndDoubleAsync()
{
    var task = AccessTheWebAsync();
    int result = await task;
    return result * 2;
}

(หรือreturn await AccessTheWebAsync() * 2;แน่นอน)


3
สามารถเสนอรายละเอียดวิธีการทำงานภายใต้ประทุนได้หรือไม่เพียงแค่อยากรู้
Freeman

8
+1 คำตอบดีๆเช่นเคย แล้วทำไมคุณถึงเขียนมันเร็วจัง!
Felix K.

9
+1: เพิ่งเริ่มมองหาasync/ awaitและฉันพบว่าสิ่งนี้ไม่ใช้งานง่ายมาก IMO ควรมีคีย์เวิร์ดหรือคำที่คล้ายกันreturnเพื่อให้ชัดเจนเช่นreturn async result;(ในลักษณะเดียวกับที่await result"แกะ" TออกจากTast<T>)
dav_i

2
@JonSkeet แต่ก็ไม่ได้ทำให้ความรู้สึกโดยไม่ต้องawaitด้วย - T foo = someTaskT;คุณจะได้รับ "ไม่สามารถปริยายแปลงชนิดTask<T>ไปT" - ในทางเดียวกันผมยืนยันว่ามันจะทำให้รู้สึกมากขึ้นที่จะมีคำหลักสำหรับผกผัน (ที่ห่อในTask<T>) ฉันทุกคนลบปุย แต่ในกรณีนี้ฉันคิดว่ามันทำให้สับสนโดยไม่จำเป็นภายในasyncวิธีการ (เห็นได้ชัดว่าประเด็นคือการสงสัยเพราะพลังที่พูด / เข้ารหัสไปแล้ว!)
dav_i

2
@dav_i: งานที่มอบหมายไม่สมเหตุสมผล แต่ส่วนที่เหลือทำ และมีบางกรณีที่ข้อความทั้งหมดจะสมเหตุสมผล - แม้ว่ามันอาจจะไม่มีประโยชน์ก็ตาม เนื่องจากมีการประกาศวิธีการแล้วasyncฉันคิดว่าเพียงพอแล้ว
Jon Skeet

18

ไม่จำเป็นต้องแปลงงานเป็น int เพียงใช้ผลงาน

int taskResult = AccessTheWebAndDouble().Result;

public async Task<int> AccessTheWebAndDouble()
{
    int task = AccessTheWeb();
    return task;
}

มันจะคืนค่าถ้ามีมิฉะนั้นจะคืนค่าเป็น 0


20
นั่นไม่ใช่สิ่งที่ฉันถาม
Freeman

16
สิ่งนี้ไม่ตอบคำถาม แต่ที่สำคัญกว่านี้เป็นคำแนะนำที่ดีมาก คุณเกือบจะควรไม่เคยใช้Result; อาจทำให้เกิดการชะงักงัน! พิจารณาตัวอย่างขั้นตอนการทำงานนี้: (1) เขียนข้อความว่า "ตัดหญ้า" (2) รอให้ตัดหญ้า (3) กินแซนวิช (4) ทำทุกอย่างที่ระบุไว้ในบันทึกย่อ "ด้วยขั้นตอนการทำงานดังกล่าวคุณจะไม่กินแซนด์วิชหรือตัดหญ้าเพราะขั้นตอนที่ 2 เป็นการรอแบบซิงโครนัสเกี่ยวกับสิ่งที่คุณจะทำในอนาคตแต่นั่นคือขั้นตอนการทำงานที่คุณกำลังอธิบายอยู่ที่นี่
Eric Lippert

@EricLippert: ไม่เคลียร์ตัวอย่างของคุณ คุณช่วยอธิบายได้ไหมว่าผลลัพธ์สามารถทำให้เกิดการหยุดชะงักเมื่อรอไม่ได้ได้อย่างไร?
CharithJ

3
การรอคอยหมายถึงการทำบางสิ่งในขณะที่คุณกำลังรอผลลัพธ์และบางสิ่งอาจรวมถึงการทำงานเพื่อคำนวณผลลัพธ์ แต่การรอแบบซิงโครนัสจะไม่ทำอะไรเลยในขณะที่คุณรอซึ่งหมายความว่าคุณอาจป้องกันไม่ให้งานเสร็จสิ้น
Eric Lippert

1
@EricLippert จะมีปัญหาเดียวกันหรือไม่ 'Task.Run (() => AccessTheWebAndDouble ()) ผลลัพธ์;'
CharithJ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.