我有一个Parser方法,它返回第一个与_Pattern匹配的位置。不幸的是,它正在积极地拉动角色。我希望它是被动的,由给出的字符驱动,这样我就可以让多个Parsers'同时'在同一个Stream上搜索不同的模式并返回第一个适合的模式。看起来应该是这样的:
Task<int>[] patterns = new Task<int>[] { };
var patternNo = Task.WaitAny(patterns);
var pattern1 = patterns[patternNo];
var found = pattern1.Result;
这是“拉”模式中的方法,用Func读取字符:
public int IndexIn(Func<char> reader) {
var currItem = reader();
for (int i, p = i = 0; ;) {
if (p == -1 || _Pattern[p] == currItem) {
++i; ++p;
currItem = reader();
} else {
p = _Prefix[p];
}
if (p >= _Pattern.Length) {
return i - _Pattern.Length;
}
}
我可以使用async / await轻松将其转换为推送驱动方法,这就是本框架之美:
public async Task<int> IsFound(Task<char> nextChar) {
var currItem = await nextChar;
for (int i, p = i = 0; ;) {
if (p == -1 || _Pattern[p] == currItem) {
++i; ++p;
currItem = await nextChar;
} else {
p = _Prefix[p];
}
if (p >= _Pattern.Length) {
return i - _Pattern.Length;
}
}
}
但是如何'驱动'这个异步方法呢?我需要构建一个将角色传递给它的Task。给定一个字符串我想将它提供给模式,如:
var completion = new TaskCompletionSource<char>();
var isFound = searcher.IsFound(completion.Task);
foreach(var chr in stringToSearchIn) {
completion.SetResult(chr);
if (isFound.IsCompleted) {
break;
}
}
return isFound.Result;
但是,即使在检索到Result之后,TaskCompletionSource仍保持完整。我可以重置吗?有没有我可以使用的替代类,或者我必须编写自己的自定义TaskCompletionSource?或者任务是仅针对单次/值吗?
答案 0 :(得分:0)
感谢您的努力。我在这里想要实现的是控制流的反转,这就是产量和异步/等待的结果。他们构建了一个可以在'yield'或'await'命令之后直接返回的状态机。 'yield'返回值,'await'检索值,因此使用这些Constructs可以在Read-Scenarios和Write-Scenarios中切换控制流。 在这种情况下,我可以提供一个Task-Factory,为我想要使用的每个角色创建一个新任务:
public class TaskFactory<T> {
public TaskCompletionSource<T> Task { get; private set; }
public Task<T> GetTask() {
Task = new TaskCompletionSource<T>();
return Task.Task;
}
}
以下客户端代码按预期工作:
var completion = new TaskFactory<char>();
var isFound = searcher.IsFound(completion.GetTask);
foreach(var chr in hayStack) {
completion.Task.SetResult(chr);
if (isFound.IsCompleted) {
break;
}
}
return isFound.Result;
这会创建一些Overhead,这使得它比同步Push-Operation慢: