问题描述
我写了以下方法:
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;
}
我有两个问题:
-
我可以简化代码吗?
-
我可以将任何无参数方法/函数传递给此方法,以获取任何类型的返回类型。例如:
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));
解决方法
我可以简化代码吗?
你既可以简化它,又可以使它更正确。所编写的代码存在一些问题:
-
IsLoading
是一个 UI 绑定属性,所以它应该在 UI 线程上更新,而不是在后台线程上。某些框架(如 Windows 上的 WPF)允许您改变规则,但其他基于 XAML 的框架则不允许。 - 如果加载失败,当前代码永远不会将
IsLoading
设置为false
。 -
Task.Factory.StartNew
should be avoided; it's a dangerous,low-level method。如果您需要在后台线程上运行方法,请使用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;
}
可以捆绑为T
的任何参数的功能的需求。
如果您仍然希望各个参数,你必须创建额外的过载。
您也可以尝试params
传递的参数的任意数目,但它们都必须是同一类型的,除非你以某种方式使用运行时多态性。
- 您可以将其稍微缩短为
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 可能是有意义的
- 我同意 Robert Harvey answer 关于附加参数的意见
有没有一种方法,我可以使这个方法更通用
一种选择是巢它像这样:
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()方法返回一个任务了。假设它很容易调整如果让你的情况没有任何意义。)