[英]How to iterate through Dictionary without using foreach
我不确定标题是否写得很好,很抱歉。
我基本上有一堆列出通信目标的元素。 尽管我愿意将它们移至其他数据结构,但仍将它们放入字典中。 我的问题是我有一个树状结构,其中一个键是一个分支,每个分支都有很多叶子。 分支和叶子的名称都存储在字符串中(不能为数字)。
private Dictionary < string, string[]> targets;
对于字典中的每个元素,我都必须发送通信,并且当目标回答时,我转到下一个目标并重新开始。 因此,在搜索之后,我面临以下困境:
我是C#的新手,所以答案可能很明显,但是我很难找到适合自己需求的数据结构。 什么是最简单的解决方案? 有人可以建议什么吗?
谢谢。
编辑
我认为我的帖子使很多人感到困惑,并且它们被卡在术语指针和线程上。 我所说的线程并不是指它们是并行的,只是我不能使用foreach或循环,因为执行下一次迭代的下一个线程是由传入通信触发的。 此机制目前无法更改,仅必须更改。 通过指针,我并不是指经常在C语言中使用的内存指针,我的意思是指向您在列表中的位置的东西。 抱歉,我是Java程序员,所以我可能会使用令人困惑的术语。
我注意到枚举器通常是继承的,并且可以与诸如Dictionary和Linked List之类的结构一起使用。 我发现了一些有关封装此子结构的示例,并以foreach循环为例。
是否可以通过某种方式使用GetEnumerator (),即使通过其他线程访问时,枚举数也会记住当前位置?
我打算自己进行测试,但是如果有经验的人提出任何建议,我们将不胜感激!
您可以使用Parallel.ForEach方法(来自.NET 4) 并行枚举此方法。 它已作为Rx框架的一部分向后移植,以在.NET 3.5sp1中使用。
注意-实际上,这实际上并不为每个项目使用一个线程,而是根据要执行的系统的硬件线程数,使用线程池对工作进行分区(通常更好。)。 在.NET 4中,它利用了ThreadPool的新爬坡和偷工算法,因此非常高效。
我认为您需要对架构进行一些重新设计,字典本身可能不是您需要用于有序迭代的数据结构。
我会考虑将您的树移到链接列表中。
当您开始进行通信时,我建议您让线程回调一个委托以更新列表数据,或者另一个共享数据结构来跟踪您在通信过程中的位置。
static LinkedList<LeafItem> TreeList = new LinkedList<LeafItem>( );
foreach (LeafItem li in TreeList) {
Thread newThread = new Thread(
new ParameterizedThreadStart(Work.DoWork));
newThread.Start(li);
}
编辑:从您的评论:
我的算法更像是:获取第一个目标将消息发送到第一个目标线程DIES-捕获端口接收事件,检查其正确的目标是否执行了某些操作-转到下一个目标,开始循环。
如果要异步处理而不是并行处理项目,则应该能够通过将字典的键复制到Queue<string>
并将两者都传递给处理异步响应的回调来实现。
您的完成处理程序pseduo代码可能如下所示:
// first extract your dictionary, key, and queue from whatever state
// object you're using to pass data back to the completion event
if (dictionary.Contains(key)) {
// process the response
}
if (queue.Count > 0) {
string key = queue.Dequeue();
string[] messages = dictionary[key];
// send the messages, along with your state data and this callback
}
这是一个有点远的镜头,我怀疑我已经把它弄乱了:/
基本上,这个想法是为字典创建一个自定义IEnumerator
。 想法是它包含一个静态变量,该变量保留枚举的“位置”以继续。
以下是一些可用于暂停和重新启动的基本代码。
public class MyDictEnumerator<T> : IEnumerator<T>
{
private List<T> Dict;
private static int curLocation = -1;
public MyDictEnumerator(List<T> dictionary)
{
Dict = dictionary;
}
public T Current
{
get { return Dict[curLocation]; }
}
public void Dispose()
{ }
object System.Collections.IEnumerator.Current
{
get { return Dict[curLocation]; }
}
public bool MoveNext()
{
curLocation++;
if (curLocation >= Dict.Count)
return false;
return true;
}
public void Reset()
{
curLocation = -1;
}
}
然后使用:
MyDictEnumerator<KeyValuePair<string, int>> enumer = new MyDictEnumerator<KeyValuePair<string, int>>(test.ToList());
while (enumer.MoveNext())
{
Console.WriteLine(enumer.Current.Value);
}
我承认这不是最干净的方法。 但是,如果您脱离枚举器,并在另一个线程上创建一个新的枚举器,则它将在同一点继续(我认为:/)
我希望这有帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.