Làm thế nào để bạn thực hiện một phương thức ủy nhiệm hành động không đồng bộ?


132

Một chút thông tin cơ bản.

Tôi đang tìm hiểu ngăn xếp API Web và tôi đang cố gắng đóng gói tất cả dữ liệu dưới dạng đối tượng "Kết quả" với các tham số như Thành công và Mã lỗi.

Tuy nhiên, các phương thức khác nhau sẽ tạo ra các kết quả và mã lỗi khác nhau nhưng đối tượng kết quả thường sẽ được khởi tạo theo cùng một cách.

Để tiết kiệm thời gian và cũng để tìm hiểu thêm về các khả năng không đồng bộ / chờ đợi trong C #, tôi đang cố gắng bọc tất cả các phần thân phương thức của các hành động api web của mình trong một đại biểu hành động không đồng bộ nhưng bị vướng vào một chút ...

Cho các lớp sau:

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;
        }
    }
}

Tôi muốn viết một phương thức thực hiện một hành động trên một đối tượng Kết quả và trả về nó. Thông thường thông qua các phương pháp đồng bộ, nó sẽ là

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

Nhưng làm cách nào để chuyển đổi phương thức này thành phương thức không đồng bộ bằng cách sử dụng async / await?

Đây là những gì tôi đã thử:

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
Nếu bạn đang thực newhiện T, tại sao phương pháp của bạn cần phải không đồng bộ? AFAIK trong mã sử dụng API không đồng bộ, bạn chỉ cần truyền bá tính chất asynctừ các phương thức khác mà bạn sử dụng.
millimoose

Xin lỗi tôi vẫn còn khá mới với điều này, ý bạn là gì khi bạn nói rằng bạn chỉ cần tuyên truyền, và T mới phải làm gì với nó?
Albin Anke

Tôi nghĩ rằng tôi đã tìm ra nó, cảm ơn millimoose bạn đã cho tôi một cái gì đó để suy nghĩ.
Albin Anke

1
Tại sao bạn thậm chí đang cố gắng để làm async này? Thường xuyên hơn trong các tình huống máy chủ web không thực hiện giả mạo bằng cách gói mã đồng bộ trong các tác vụ (như bạn đang cố gắng thực hiện) chậm hơn so với chỉ thực hiện đồng bộ.
Scott Chamberlain

1
@AlbinAnke Bằng cách "tuyên truyền" Ý tôi là nếu bạn đang gọi một phương thức .NET như Stream.ReadAsync()trong một phương thức, thì phương thức đó sẽ không đồng bộ và trả về một Task<T>nơi Tmà bạn đã trả về là phương thức đồng bộ. Ý tưởng là theo cách này, mọi người gọi phương thức của bạn sau đó có thể "chờ đợi không đồng bộ" (tôi không biết thuật ngữ tốt cho việc này là gì) Stream.ReadAsync()để hoàn thành bên dưới . Một phép ẩn dụ cho điều này bạn có thể sử dụng là async là "lây nhiễm" và lây lan từ I / O tích hợp cấp thấp sang mã khác có kết quả phụ thuộc vào I / O đã nói.
millimoose

Câu trả lời:


307

Các asynctương đương Action<T>Func<T, Task>, vì vậy tôi tin rằng đây là những gì bạn đang tìm kiếm:

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

@Stephen Rõ ràng tôi đang cố gắng thực hiện một số tương tự với Messenger ligth MVVM, tôi có thể thực hiện theo cách tương tự không?
Juan Pablo Gomez

@JuanPabloGomez: Tôi không quen thuộc với loại tin nhắn của họ, nhưng tôi không hiểu tại sao nó không hoạt động.
Stephen Cleary

1
Thật đáng kinh ngạc! Tôi nghĩ rằng sẽ không thể thực hiện Hành động không đồng bộ và đã coi đó là một lỗ hổng ngôn ngữ. Tôi đã không nghĩ về việc sử dụng Func. Cảm ơn.
Noel Widmer

2
@DFSFOT: Tương đương async của một voidphương thức là một Taskphương thức hoàn trả; do đó, tương đương async ActionFunc<Task>và tương đương async Action<T>Func<T, Task>. Thêm thông tin ở đây .
Stephen Cleary

1
@DFSFOT: Phương thức async sẽ trả về Taskkhi nó không có giá trị trả về. Nếu nó sử dụng asynctừ khóa, thì thể hiện thực tế Tasksẽ được tạo bởi một máy trạng thái, không phải là hàm trực tiếp.
Stephen Cleary

-11

Vì vậy, tôi tin rằng cách để thực hiện điều này là:

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
Bạn nên tránh Task.Run(và thậm chí nhiều hơn thế StartNew) trên ASP.NET.
Stephen Cleary

Một cách tốt hơn để làm điều này là gì?
Albin Anke

Tôi đã đăng một câu trả lời, và câu trả lời của @ Svick cũng vậy. Cả hai đều là câu trả lời tốt.
Stephen Cleary
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.