我正在开发一个从Beckhoff PLC读取值的应用程序。 plc有一个.net库,我可以用它来连接我的程序和PLC。
PLC上的每个变量都是TcAdsSymbolInfo类型的符号。这个类有几个成员,其中一个是TcAdsSymbolInfo的集合等等......你可以看到它的发展方向。基本上我有一个树形结构,有许多符号,每个符号可以有子符号。 Beckhoff
我想要做的是,对于每个符号读取所有子符号,如果我手工完成并尝试查看第一个子符号级别,这是有效的,但我真的需要所有这些。
我试图创建一个递归函数,它接收一个TcAdsSymbolInfo并在最后调用它自己,但这会抛出一个Stack Overflow异常
private void ReadSubsymbols(TcAdsSymbolInfo t)
{
if (t.SubSymbolCount > 0)
{
foreach (TcAdsSymbolInfo subsymbol in t.SubSymbols)
{
if (!symbols.ContainsKey(subsymbol.Name))
symbols.Add(subsymbol.Name, subsymbol);
try
{
ReadSubsymbols(subsymbol);
}
catch (Exception Ex)
{
Console.WriteLine(Ex.ToString() + " - " + Ex.Message);
}
}
}
}
符号只是一个字典,我存储符号名称和符号本身。
请尝试从PLC部分摘要,因为我认为这只是一个纯粹的逻辑/编程问题。在与PLC通信或读写值时没有任何问题。唯一的问题是阅读该结构。
我可以使用一段时间或任何其他类型的循环对此进行任何分析吗?什么都没有抛出异常?
提前致谢。
答案 0 :(得分:2)
您可以使用迭代树遍历。 但在尝试此之前,请确保堆栈溢出是由于递归变得太深。它很可能是一个编码错误,允许递归无限下降。
您可以执行以下Psuedo代码:
Push root node to stack
While (stack is not empty)
{
current node = pop from stack
process current node (and other processing goes here)
add all children with nodes to stack
}
请参阅此示例以解决与目录类似的问题: http://msdn.microsoft.com/en-us/library/bb513869.aspx
答案 1 :(得分:1)
这是一个简单的树步行。基本逻辑是从根开始:
易。主要是:D你遇到麻烦的地方是你在图中遇到周期时(例如,当一个子节点链接回一个自己的父节点时)。如果你有周期,你必须跟踪你访问过的节点(就像我的例子那样),并在你去的时候检查周期(我的例子没有)。
鉴于这样的课程:
class SymbolInfo
{
public string Name { get ; set ; }
public SortedSet<SymbolInfo> Subsymbols { get ; set ; }
public SymbolInfo( string name )
{
this.Name = name ;
this.Subsymbols = new SortedSet<SymbolInfo>( new SymbolInfo.Comparer() ) ;
}
public override string ToString()
{
return this.Name ?? "-null-" ;
}
private class Comparer : IComparer<SymbolInfo>
{
public int Compare( SymbolInfo x , SymbolInfo y )
{
return string.Compare(x.Name,y.Name,StringComparison.InvariantCultureIgnoreCase) ;
}
}
}
树步行看起来像这样:
public static IEnumerable<string> TreeWalk( SymbolInfo root , List<SymbolInfo> visited )
{
if ( root != null )
{
visited.Add(root) ;
yield return string.Join( " -> " , visited ) ;
foreach ( SymbolInfo child in root.Subsymbols )
{
foreach ( string childPath in TreeWalk( child , visited ) )
{
yield return childPath ;
}
}
visited.RemoveAt(visited.Count-1) ;
}
}
给出一个这样构造的树:
private static SymbolInfo LoadTree()
{
SymbolInfo a = new SymbolInfo("A") ;
SymbolInfo b = new SymbolInfo("B") ;
SymbolInfo c = new SymbolInfo("C") ;
SymbolInfo d = new SymbolInfo("D") ;
SymbolInfo e = new SymbolInfo("E") ;
SymbolInfo f = new SymbolInfo("F") ;
SymbolInfo g = new SymbolInfo("G") ;
SymbolInfo h = new SymbolInfo("H") ;
SymbolInfo i = new SymbolInfo("I") ;
a.Subsymbols.Add(b) ;
a.Subsymbols.Add(c) ;
a.Subsymbols.Add(d) ;
b.Subsymbols.Add(e) ;
c.Subsymbols.Add(f) ;
c.Subsymbols.Add(g) ;
f.Subsymbols.Add(h) ;
f.Subsymbols.Add(i) ;
return a ;
}
我们可以像这样调用它:
SymbolInfo root = LoadTree() ;
foreach ( string path in TreeWalk( root , new List<SymbolInfo>() ) )
{
Console.WriteLine(path) ;
}
产生以下输出:
A
A -> B
A -> B -> E
A -> C
A -> C -> F
A -> C -> F -> H
A -> C -> F -> I
A -> C -> G
A -> D
答案 2 :(得分:0)
public IEnumerable<TcAdsSymbolInfo> GetSymbols(IEnumerable<TcAdsSymbolInfo> set)
{
if (!set.Any())
return Enumerable.Empty<TcAdsSymbolInfo>();
return set.SelectMany(sym => GetSymbols(sym.SubSymbols)));
}
然后,您可以将结果转换为字典并检查欺骗等。