我有一个由多个项目引用的View Model
或Views
。
由于API,部分View
项目为async
而其他项目则不是。{/ p>
View
项目使用IOC容器将其实现的接口注入View Model
。
考虑这个代码的最小例子
界面:
public interface IDatabase
{
Task<Data> GetData();
}
View Model
等待GetData方法:
public class DisplayDataViewModel
{
private readonly IDatabase _database
public DisplayDataViewModel(IDatabase database)
{
_database = database;
}
private async Task GetDataFromDatabase()
{
Data data = await _database.GetData();
// do something with data...
}
}
Asynchronous View
项目使用Async函数获取数据
public class AsynchronousViewDataBase : IDatabase
{
public async Task<Data> GetData()
{
return await GetDataAsync();
}
}
Synchronous View
项目使用同步调用来获取数据,但由于接口的约束,我需要返回一个Task,但我只对返回Data
感兴趣使方法异步。
public class SynchronousViewDatabase : IDatabase
{
public async Task<Data> GetData()
{
return GetData();
}
}
但是然后会发出警告:
这种异步方法缺少'await'运算符并将同步运行。考虑使用'await'运算符等待非阻塞API调用,或'await Task.Run(...)'在后台线程上执行CPU绑定工作。
这对我很好,因为我不在乎它是否同步运行。
使用Task.Run
来抑制警告似乎是不必要的,因为调用可以(在我的情况下)来自后台线程。
是否有最佳实践来实现此类非等待异步方法?可以忽略警告吗?有没有更好的方法来实现 async 同步调用?
我确实将界面转换为同步调用,并使用Task.Result
中的Asynchronous View
(修复了警告),但这导致应用停止响应并出现了很多难题
注意:我不声明使用async
关键字神奇地使该方法异步运行。
答案 0 :(得分:9)
async
是一个实现细节,因此如果您不使用await
,可以将其从方法中删除,然后您可以使用Task.FromResult
返回已完成的任务并获得所需的结果
public class SynchronousViewDatabase : IDatabase
{
public Task<Data> GetData()
{
return Task.FromResult<Data>(GetData());
}
}
答案 1 :(得分:5)
是否有最佳实践来实现此类非等待异步方法?
是的,它称为同步API 。不要强迫那些自然不同步的代码。添加GetData
方法,该方法返回string
。
只要您了解其含义,可以忽略警告吗?
确定。调用可能从异步方法长时间运行的同步方法可能会让这个方法的消费者感到惊讶,因为它实际上会阻塞。 此外,还有一个事实是,任何异常都将通过生成的{ - 1}}状态机进行封装。当然还有状态机本身和任何解除操作员的小开销。
有没有更好的方法来实现异步同步调用?
这实际上取决于用例。如果这是一个不明显的简短操作,您可以使用Task
并删除Task.FromResult
修饰符(如其他人所说)或将调用推迟到线程池线程。从你的问题我明白你也不想要。
答案 2 :(得分:3)
您的界面应实现两种不同的方法,让调用者决定是否需要异步或同步
Data GetData();
和
Task<Data> GetDataAsync();
这是运行异步方法synchron的可能方法
public class SynchronousViewDatabase : IDatabase
{
public Data GetData()
{
var getDataTask = GetDataAsync();
getDataTask.RunSynchroniously();
if(getDataTask.Status == TaskStatus.RanToCompletion)
return getDataTask.Result;
throw getDataTask.Exception;
}
}