簡體   English   中英

使用通用函數的異步方法<t></t>

[英]Async Method Using Generic Func<T>

我寫了以下方法:

async Task<T> Load<T>(Func<T> function)
{
    T result = await Task.Factory.StartNew(() =>
    {
        IsLoading = true;

        T functionResult = function.Invoke();

        IsLoading = false;

        return functionResult;
    });

    return result;
}

我有兩個問題:

  1. 我可以簡化代碼嗎?

  2. 我可以將任何無參數方法/函數傳遞給此方法以獲得任何類型的返回類型。 例如:

     string GetString()

    通過說:

     string someString = await Load(GetString);

    有沒有辦法讓這個方法更通用,以便我也可以傳遞帶參數的方法? 例如,一種也可以接受的單一方法:

     string GetString(string someString) string GetString(string someString, int someInt)

    這可能看起來像:

     string someString = await Load(GetString("string")); string someString = await Load(GetString("string", 1));

    這顯然是行不通的,但是由於Load<T>方法沒有引用參數,我覺得這應該是可能的。

我可以簡化代碼嗎?

您既可以簡化它,也可以使它更正確。 編寫的代碼存在一些問題:

  1. IsLoading是一個 UI 綁定屬性,因此它應該在 UI 線程上更新,而不是在后台線程上。 某些框架(例如 Windows 上的 WPF)允許您改變規則,但其他基於 XAML 的框架則不允許。
  2. 如果加載失敗,代碼當前不會將IsLoading設置為false
  3. 應避免Task.Factory.StartNew 這是一種危險的低級方法 如果您需要在后台線程上運行方法,請使用Task.Run
async Task<T> Load<T>(Func<T> function)
{
  IsLoading = true;
  try
  {
    return await Task.Run(function);
  }
  finally
  {
    IsLoading = false;
  }
}

有沒有辦法讓這個方法更通用,以便我也可以傳遞帶參數的方法?

您可以為此使用 lambda:

string someString = await Load(() => GetString("string"));
string someString = await Load(() => GetString("string", 1));

有沒有辦法讓這個方法更通用,以便我也可以傳遞帶參數的方法?

async Task<R> Load<T, R>(Func<T, R> function, T parameter)
{
    R result = await Task.Run(() =>
    {
        return function.Invoke(parameter);
    });

    return result;
}

您可以將 function 需要的任何參數捆綁到T中。

如果您仍然需要單個參數,則必須創建額外的重載。

您也可以嘗試params傳遞任意數量的參數,但它們必須都是相同類型,除非您以某種形式使用運行時多態性。

  1. 您可以將其稍微縮短為
Task<T> Load<T>(Func<T> function)
{
    return Task.Factory.StartNew(() =>
    {
        IsLoading = true;
        var functionResult = function.Invoke();
        IsLoading = false;

        return functionResult;
    });
}

async 和 await 是可選的,因為您可以返回任務。 在 finally 中使用 try... finally 阻止和更新 IsLoading = false 可能是有意義的

  1. 我同意 Robert Harvey 關於附加參數的回答

有沒有辦法讓這個方法更通用

一種選擇是像這樣嵌套它:

    public bool IsLoading { get; set; }
    
    public Task<string> GetString(string input) => Task.FromResult($"ret for input {input}");

    public async Task<TReturn> Load<TReturn>(Func<Task<TReturn>> cb)
    {
        IsLoading = true;
        var ret = await cb();
        IsLoading = false;

        return ret;
    }

    public async Task Demo()
    {
        var ret = await Load(() => GetString("input"));
    }

(我也讓 GetString() 方法返回了一個任務。假設如果這對你的情況沒有意義,那么它很容易調整。)

暫無
暫無

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

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