คุณใช้วิธีการมอบหมายการดำเนินการ async อย่างไร


133

ข้อมูลพื้นฐานเล็กน้อย

ฉันกำลังเรียนรู้ Web API stack และฉันกำลังพยายามห่อหุ้มข้อมูลทั้งหมดในรูปแบบของออบเจ็กต์ "Result" ด้วยพารามิเตอร์เช่น Success และ ErrorCodes

อย่างไรก็ตามวิธีการที่แตกต่างกันจะให้ผลลัพธ์และรหัสข้อผิดพลาดที่แตกต่างกัน แต่โดยทั่วไปวัตถุผลลัพธ์จะถูกสร้างอินสแตนซ์ในลักษณะเดียวกัน

เพื่อประหยัดเวลาและเรียนรู้เพิ่มเติมเกี่ยวกับความสามารถ async / await ใน C # ฉันพยายามที่จะรวมเนื้อหาวิธีการทั้งหมดของการกระทำเว็บ api ของฉันในตัวแทนการกระทำแบบอะซิงโครนัส แต่ติดอยู่ในอุปสรรคเล็กน้อย ...

ให้ชั้นเรียนต่อไปนี้:

public class Result
{
    public bool Success { get; set; }
    public List<int> ErrorCodes{ get; set; }
}

public async Task<Result> GetResultAsync()
{
    return await DoSomethingAsync<Result>(result =>
    {
        // Do something here
        result.Success = true;

        if (SomethingIsTrue)
        {
            result.ErrorCodes.Add(404);
            result.Success = false;
        }
    }
}

ฉันต้องการเขียนวิธีที่ดำเนินการกับวัตถุผลลัพธ์และส่งคืน โดยปกติจะใช้วิธีซิงโครนัส

public T DoSomethingAsync<T>(Action<T> resultBody) where T : Result, new()
{
    T result = new T();
    resultBody(result);
    return result;
}

แต่ฉันจะเปลี่ยนวิธีนี้เป็นวิธีอะซิงโครนัสโดยใช้ async / await ได้อย่างไร

นี่คือสิ่งที่ฉันได้ลอง:

public async Task<T> DoSomethingAsync<T>(Action<T, Task> resultBody) 
    where T: Result, new()
{
    // But I don't know what do do from here.
    // What do I await?
}

1
หากคุณกำลังnewใช้งานอยู่Tเหตุใดวิธีการของคุณจึงต้องเป็นแบบอะซิงโครนัส AFAIK ในโค้ดโดยใช้ API แบบอะซิงโครนัสคุณจะต้องเผยแพร่asyncness จากวิธีการอื่นที่คุณใช้เท่านั้น
มิลลิโมส

ขออภัยฉันค่อนข้างใหม่สำหรับสิ่งนี้คุณหมายความว่าอย่างไรเมื่อคุณบอกว่าคุณต้องการเผยแพร่เท่านั้นและสิ่งที่เกิดขึ้นใหม่กับ T เกี่ยวข้องกับมันอย่างไร?
Albin Anke

ฉันคิดว่าฉันคิดออกแล้วขอบคุณมิลลิโมสที่คุณให้ฉันคิดบางอย่าง
Albin Anke

1
ทำไมคุณถึงพยายามทำ async นี้? บ่อยครั้งที่ไม่ได้อยู่ในสถานการณ์เว็บเซิร์ฟเวอร์ที่ทำ async ปลอมโดยการห่อรหัสซิงโครนัสในงาน (เช่นที่คุณพยายามทำ) นั้นช้ากว่าการทำพร้อมกัน
Scott Chamberlain

1
@AlbinAnke โดย "เผยแพร่" ฉันหมายความว่าหากคุณกำลังเรียกใช้เมธอด. NET เหมือนStream.ReadAsync()ในเมธอดเมธอดนั้นควรเป็นแบบอะซิงโครนัสและส่งคืนTask<T>ตำแหน่งTที่คุณส่งกลับมาคือเมธอดซิงโครนัส แนวคิดก็คือด้วยวิธีนี้ผู้เรียกใช้วิธีการของคุณทุกคนจะสามารถ "รอแบบอะซิงโครนัส" (ฉันไม่รู้ว่าคำนี้เป็นคำที่ดี) เพื่อให้การอ้างอิงStream.ReadAsync()เสร็จสมบูรณ์ อุปมาสำหรับสิ่งนี้ที่คุณสามารถใช้ได้คือ async คือ "การติดเชื้อ" และแพร่กระจายจาก I / O ในตัวระดับต่ำไปยังโค้ดอื่น ๆ ซึ่งผลลัพธ์จะขึ้นอยู่กับ I / O ที่กล่าวไว้
มิลลิโมส

คำตอบ:


307

สิ่งที่asyncเทียบเท่าAction<T>คือFunc<T, Task>ดังนั้นฉันเชื่อว่านี่คือสิ่งที่คุณกำลังมองหา:

public async Task<T> DoSomethingAsync<T>(Func<T, Task> resultBody)
    where T : Result, new()
{
  T result = new T();
  await resultBody(result);
  return result;
}

@Stephen เห็นได้ชัดว่าฉันกำลังพยายามนำสิ่งที่คล้ายกันไปใช้ใน MVVM ligth Messenger ฉันสามารถใช้วิธีเดียวกันได้หรือไม่?
Juan Pablo Gomez

@JuanPabloGomez: ฉันไม่คุ้นเคยกับการส่งข้อความของพวกเขา แต่ฉันไม่เห็นว่าทำไมมันถึงใช้ไม่ได้
Stephen Cleary

1
สิ่งนี้ช่างมหัศจรรย์! ฉันคิดว่ามันเป็นไปไม่ได้ที่จะสร้าง async Action และถือว่าเป็นข้อบกพร่องของภาษาแล้ว ฉันไม่ได้คิดเกี่ยวกับการใช้ Func ขอบคุณ
Noel Widmer

2
@DFSFOT: การเทียบเท่า async ของvoidเมธอดคือ a Task-returning method; จึงเทียบเท่า async ของActionมีFunc<Task>และเทียบเท่า async ของมีAction<T> Func<T, Task>ข้อมูลเพิ่มเติมที่นี่
Stephen Cleary

1
@DFSFOT: วิธีการ async ควรส่งคืนTaskเมื่อไม่มีค่าส่งคืน หากใช้asyncคีย์เวิร์ดTaskอินสแตนซ์จริงจะถูกสร้างขึ้นโดยเครื่องของรัฐไม่ใช่ฟังก์ชันโดยตรง
Stephen Cleary

-11

ดังนั้นฉันเชื่อว่าวิธีการนำไปใช้คือ:

public Task<T> DoSomethingAsync<T>(Action<T> resultBody) where T : Result, new()
{
    return Task<T>.Factory.StartNew(() =>
    {
        T result = new T();
        resultBody(result);
        return result;
    });
}

7
คุณควรหลีกเลี่ยงTask.Run(และมากกว่านั้นStartNew) ใน ASP.NET
Stephen Cleary

วิธีที่ดีกว่านี้คืออะไร?
Albin Anke

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