簡體   English   中英

帶參數的異步lambda表達式

[英]async lambda expression with arguments

我試圖從包裝器調用我的異步函數。 但是我收到了這個編譯錯誤。 在下面的代碼中,我想得到string x值,大部分等待抽象/推入CallAsyncFunc代碼。 在c#4.5中執行此操作的正確方法是什么? 謝謝!

錯誤CS4010:無法將異步lambda表達式轉換為委托類型' System.Func<int,string> '。 異步lambda表達式可能返回voidTaskTask<T> ,其中任何一個都不能轉換為' System.Func<int,string> '。

public async Task<T2> CallAsyncFunc<T1,T2>(T1 a, Func<T1, T2> func)
{
    return func.Invoke(a);
}

public async Task<string> GetString(int value)
{
    await Task.Run(() => Thread.Sleep(2000));
    return "" + value;
}

public async Task MainAsyncEntry()
{
    string x = await CallAsyncFunc<int, string>(30, async(x) => await GetString(x));
}

在:

string x = await CallAsyncFunc<int, string>(30, async(x) => await GetString(x));

第一個問題你有兩個x 嘗試:

string y = await CallAsyncFunc<int, string>(30, async(x) => await GetString(x));

這里lambda的輸出是string但因為你使用async它應該是一個TaskTask<T>

你可以寫:

string y = await CallAsyncFunc<int, string>(30, x => GetString(x).Result);
// Equivalent to
string y = await CallAsyncFunc(30, x => GetString(x).Result);

要么

string y = await CallAsyncFunc<int, Task<string>>(30, x => GetString(x)).Result;
// Equivalent to
string y = await CallAsyncFunc(30, GetString).Result;

但在任何一種情況下,您的CallAsyncFunc都將同步運行,因為它不包含任何await

這是做這件事的好方法:

// This
public async Task<TOut> CallAsyncFunc<TIn, TOut>(TIn input, Func<TIn, Task<TOut>> func)
{
    return await func.Invoke(input);
}

// Or those
public Task<TOut> CallAsyncFunc<TIn, TOut>(TIn input, Func<TIn, Task<TOut>> func)
{
    return func.Invoke(input);
}

public async Task<string> GetString(int value)
{
    await Task.Run(() => Thread.Sleep(2000));
    return value.ToString(CultureInfo.InvariantCulture);
}

public async Task MainAsyncEntry()
{
    string y = await CallAsyncFunc(30, GetString);
}

備注1: await GetString(x)Task<string> CallAsyncFunc包為string ,然后CallAsyncFunc再次包裝到Task<string> 您應該將包裝的表達式保持在調用堆棧的整個長度。 據我所知,這是推薦的方式。

備注2:Resharper警告CallAsyncFunc:

這種異步方法缺少“等待”運算符並將同步運行。 考慮使用'await'運算符等待非阻塞API調用,或'await TaskEx.Run(...)'在后台線程上執行CPU綁定工作

實際上,您可以省略async關鍵字並避免重新包裝到Task<string>

作為備注1和備注2的結果,您可以編寫以下colde:

// REALLY ASYNC METHOD, WRAPS THE RESULT INTO Task<string>
public async Task<string> GetString(int value)
{
    await Task.Run(() => Thread.Sleep(2000));
    return "" + value;
}

// NOT ASYNC ANY MORE: DOES NOT WRAP THE RESULT INTO Task<T2> any more
public T2 CallAsyncFunc<T1, T2>(T1 a, Func<T1, T2> func)
{
    return func.Invoke(a);
}

// WAIT FOR THE ASYNC RESULT ONLY IN THE OUTER SCOPE (UNWRAPS Task<string> BY THE WAY)
string y = await CallAsyncFunc(30, GetString);
string z = await CallAsyncFunc<int, Task<string>>(30, GetString); 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM