2013-06-21 34 views
18

Tôi có một phương pháp async bên trong một thư viện lớp di động với chữ ký này:Chuyển đổi biểu thức lambda không đồng bộ thành loại ủy quyền System.Func <T>?

private async Task<T> _Fetch<T>(Uri uri) 

Nó lấy một tài nguyên được đúc lại như một loại T. bê tông

Tôi đang làm việc với một bộ nhớ cache bên thứ 3 thư viện (Akavache) mà đòi hỏi một Func<T> là một trong những thông số và đã cố gắng làm như vậy theo cách này:

await this.CacheProvider.GetOrCreateObject<T>(key, 
    async() => await _Fetch<T>(uri), cacheExpiry); 

Điều này dẫn đến các lỗi:

Cannot convert async lambda expression to delegate type ' System.Func<T> '. An async lambda expression may return void , Task or Task<T> , none of which are convertible to ' System.Func<T> '.

Tôi đã thử hoán vị khác nhau của Func<T> phân công mà không cần bất kỳ may mắn, cách duy nhất tôi có thể lấy mã để làm việc là để làm cho Func<T> chặn:

await this.CacheProvider.GetOrCreateObject<T>(key, 
    () => _Fetch<T>(uri).Result, cacheExpiry); 

mà bế tắc ứng dụng của tôi.

Bất kỳ con trỏ nào về nơi tôi sẽ đi lạc?

+0

Bạn đang tìm kiếm 'Func ' –

Trả lời

13

Không thể làm được. Khi ai đó mong đợi một Func<T> f bạn có thể giả định nó sẽ được gọi với một cái gì đó như result = f() - tức là, nó không biết về hành vi không đồng bộ. Nếu bạn lừa nó bằng cách sử dụng .Result như bạn có - nó sẽ bế tắc trên chuỗi giao diện người dùng vì nó muốn lập lịch mã sau await (trong _Fetch) trên chuỗi giao diện người dùng, nhưng bạn đã chặn nó bằng .Result.

Đồng bộ lambda có thể được chuyển đến Action vì không có giá trị trả lại - hoặc đến Func<Task> hoặc Func<Task<T>>.

Nhìn vào trường hợp của bạn, GetOrCreateObject dường như đang gọi GetOrFetchObject. Một trong các quá tải GetOrFetchObject chấp nhận Func<Task<T>>. Bạn có thể thử gọi phương thức đó với lambda không đồng bộ của bạn và xem nó có giúp ích gì không.

+3

Tôi muốn nhấn mạnh rằng nếu một phương thức chấp nhận một 'Hành động' và bạn chuyển nó thành một lambda' async', thì đó là điều không đúng, hầu hết thời gian. – svick

+0

@svick: Có đồng ý với bạn. Cũng giống như phương thức chấp nhận 'Func ', phương thức chấp nhận một 'Hành động' sẽ không biết về hành vi không đồng bộ của nó.Async lambda mà không trả về bất kỳ kết quả nào sẽ được chuyển đến 'Func '. Nó chỉ là trình biên dịch C# cho phép nó được chuyển tới 'Action' vì không có giá trị trả về. – YK1

+0

Cảm ơn YK1, bây giờ tôi cảm thấy khá ngớ ngẩn - tôi đã triển khai giao diện trừu tượng hóa nhà cung cấp bộ nhớ cache và bỏ lỡ phương thức thay thế trên thư viện cơ sở. –

-3

Một cái gì đó như thế này?

Public Func<T> ConvertTask<T>(Task<T> task) 
{ 
    return()=>task.Result; 
} 
+0

Câu hỏi rõ ràng nói rằng việc sử dụng 'Result' gây ra bế tắc. – svick

4

YK1's answer giải thích lý do bạn không thể xử lý Func<T> như không đồng bộ.

Để khắc phục sự cố của bạn, hãy sử dụng GetOrFetchObject thay vì GetOrCreateObject. Các phương thức "create" giả sử một sự tạo (đồng bộ), trong khi các phương thức "fetch" làm việc với việc thu hồi (không đồng bộ).

await CacheProvider.GetOrFetchObject<T>(key,() => _Fetch<T>(uri), cacheExpiry) 

Tôi cũng loại bỏ các không cần thiết async/await trong biểu thức lambda của bạn. Vì _Fetch đã trả về Task<T>, không cần phải tạo một lambda async có mục đích duy nhất là await nhiệm vụ đó.

+0

Cảm ơn Stephen, đây chính xác là cách tôi giải quyết vấn đề. –

Các vấn đề liên quan