Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
406 views
in Technique[技术] by (71.8m points)

c# - Async Method Using Generic Func<T>

I have written the following method:

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

I have two questions:

  1. Can I simplify the code?

  2. I can pass any parameterless method/function to this method to get a return type of any type. E.g.:

     string GetString()
    

    By saying:

     string someString = await Load(GetString);
    

    Is there a way I could make this method more generic so that I could pass methods with parameters as well? E.g. One single method that would also accept:

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

    This might look like:

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

    This obviously doesn't work, but as the Load<T> method doesn't reference the parameters, I feel this should be possible somehow.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Can I simplify the code?

You can both simplify it, and make it more correct. There are a few problems with the code as-written:

  1. IsLoading is a UI-bound property, so it should be updated on the UI thread, not a background thread. Some frameworks like WPF on Windows allow you to bend the rules, but other XAML-based frameworks do not.
  2. The code currently will not ever set IsLoading to false if the loading fails.
  3. Task.Factory.StartNew should be avoided; it's a dangerous, low-level method. Use Task.Run if you need to run a method on a background thread.
async Task<T> Load<T>(Func<T> function)
{
  IsLoading = true;
  try
  {
    return await Task.Run(function);
  }
  finally
  {
    IsLoading = false;
  }
}

Is there a way I could make this method more generic so that I could pass methods with parameters as well?

You can use lambdas for this:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...