基于 this精彩的 CQRS 文章,我定义了以下接口(interface):
public interface IQuery<TResult>
{
}
public interface IQueryHandler<TQuery, TResult> where TQuery : IQuery<TResult>
{
TResult Handle(TQuery query);
}
实现通用异步 QueryHandler 的最佳方法是什么?到目前为止,我有一个新的接口(interface)定义来将 Handle() 方法更改为 void 并接受一个新的“Complete”事件处理程序。像这样的东西:
public interface IQueryHandlerAsync<TQuery, TResult> where TQuery : IQuery<TResult>
{
void Handle(TQuery query, RunWorkerCompletedEventHandler complete);
}
我可以为所有实现 IQueryHandlerAsync 接口(interface)的查询处理程序创建新的具体类,例如:
public class FindUsersBySearchTextQueryHandlerAsync
: IQueryHandlerAsync<FindUsersBySearchTextQuery, User[]>
{
private readonly IQueryHandler<FindUsersBySearchTextQuery, User[]> queryHandler;
public FindUsersBySearchTextQueryHandler(IQueryHandler<FindUsersBySearchTextQuery, User[]> queryHandler)
{
this.queryHandler = queryHandler;
}
public void Handle(FindUsersBySearchTextQuery query, RunWorkerCompletedEventHandler complete)
{
var worker = new BackgroundWorker();
worker.DoWork += DoWork;
worker.RunWorkerCompleted += complete;
worker.RunWorkerAsync(query);
}
void DoWork(object sender, DoWorkEventArgs e)
{
FindUsersBySearchTextQuery query = (FindUsersBySearchTextQuery)e.Argument;
queryHandler.Handle(query);
}
}
这个 Async 具体类对于我的所有查询都非常相似。有没有办法使这个通用并可能自动注入(inject)?
编辑:解决方案
保留接口(interface),但更改 Handle() 方法以返回任务:
public interface IQuery<TResult> { }
public interface IQueryHandler<TQuery, TResult> where TQuery : IQuery<TResult>
{
Task<TResult> Handle(TQuery query);
}
在具体实现中将Handle()方法的工作封装到一个Task中,启动任务,然后返回。
public Task<User[]> Handle(FindUsersBySearchTextQuery query)
{
return TaskEx.Run(() =>
{
//Do slow operation
//...
return new User[] { ... };
});
}
用法:
private async void GetUsers()
{
var users = await queryHandler.Handle(new FindUsersBySearchTextQuery
{
SearchText = searchText
});
}
最佳答案
您无需执行任何操作。只需返回 Task<T>
:
public class FindUsersBySearchTextQuery : IQuery<Task<User[]>>
{
}
public class FindUsersBySearchTextQueryHandler
: IQueryHandler<FindUsersBySearchTextQuery, Task<User[]>>
{
public async Task<User[]> Handle(FindUsersBySearchTextQuery query)
{
// ...
}
}
Task<T>
是 .NET 4.0 的一部分,因此您可以使用它。您可以使用 C# 5.0,这样您就可以使用新的 async/await 关键字,从而使编程变得更加容易。如果这不可用,您仍然可以使用 .NET 4.0 中的 TPL API 来实现这一点。
另一方面,如果您确定所有查询始终是异步的,则可以将接口(interface)更改为以下内容:
public interface IQuery<TResult> { }
public interface IQueryHandler<TQuery, TResult> where TQuery : IQuery<TResult>
{
// Note the Task<T> here
Task<TResult> Handle(TQuery query);
}
这种方法通常更好,因为现在您将有关事物是否异步的知识从查询定义中移出。查询定义(例如 class FindUsersBySearchTextQuery : IQuery<User[]>
)应该只关心返回哪些数据,sonmething 是否异步是一个实现细节(不幸的是,infects your call stack like a virus 是一个实现细节,但仍然是一个实现细节)。
关于c# - 通用异步查询类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25324997/