2012-03-02 12 views
0

私はControlCollectionの特定のTypeのインスタンスを検索し、見つかった最初のインスタンスを返すSystem.Web.UI.Controlの拡張メソッドを作成しようとしています。深さ優先は単純ですが、より高いコレクションが優先されるように、まず幅を検索したいと思います。C#コントロールコレクションの幅広い最初の検索

私の現在のメソッドには欠陥があり、早期に終了し、検索全体が完了しなかった場合にnullを返します。私は正しい解決策に近いと思っていますが、それに対して新鮮な目が必要です。助言がありますか?

public static T FindFirstControlOfType<T>(this Control rootControl, bool searchRecursively) where T : Control 
{ 
    // list for container controls 
    List<Control> controlsWithChildren = new List<Control>(); 

    // iterate the current control collection first 
    foreach (Control child in rootControl.Controls) 
    { 
     if (child.GetType().IsAssignableFrom(typeof(T))) 
     { 
      return (T)child; 
     } 

     // track those controls containing children 
     if (child.HasControls()) 
     { 
      controlsWithChildren.Add(child); 
     } 
    } 

    // if recursion is enabled, search the child nodes 
    if (searchRecursively) 
    { 
     foreach (Control control in controlsWithChildren) 
     { 
      return FindFirstControlOfType<T>(control, true); 
     } 
    } 

    // if never found, return null 
    return null; 
} 

EDIT - 作業溶液マークされた回答に基づいて、興味がある人のために:

public static T FindFirstControlOfType<T>(this Control rootControl, bool searchNestedControls) where T : Control 
{ 
    Queue<Control> queue = new Queue<Control>(); 

    EnqueueChildControls(queue, rootControl); 
    while (queue.Count > 0) 
    { 
     Control current = queue.Dequeue(); 

     if (current.GetType() == typeof(T)) 
     { 
      return (T)current; 
     } 

     if (searchNestedControls) 
     { 
      EnqueueChildControls(queue, current); 
     } 
    } 
    return null; 

} 

private static void EnqueueChildControls(Queue<Control> queue, Control control) 
{ 
    foreach (Control current in control.Controls) 
    { 
     queue.Enqueue(current); 
    } 
} 

答えて

5

幅優先探索(擬似コード)

Queue fringe 

fringe.Enqueue(rootControl) 

while(fringe.Count > 0) 
{ 
    current = fringe.Dequeue() 
    Visit(current) 
    fringe.EnqueueAll(current.Children) 
} 

ための再帰の必要はありません幅広い最初の検索。

Visitは、現在のオブジェクトで何をしても構いません。あなたが何かを探しているなら、Visitは意味します:if(current matches criteria) return current

更新: の作業例:https://gist.github.com/1960108

+0

ありがとうAndre - 私はこれを実装しようとします。幅広い最初の検索が必要なので、私は錆びているので、しばらくしています。 –

+0

私もそうでしたが、最近私はBFSをする必要がありました。そして私は実装が簡単ではなかったことを思い出しました。幸運にも、もし助けが必要なら私たちに知らせてください。 –

+1

サイドノートでは、再帰を使用するのではなく、キューをスタックに変更するだけで、このBFSを深さに変えることができます。また、優先順位キューを使用して、最善の検索を行うこともできます。すべてのインターフェイスが共通の場合は、単純な構成変更によってアルゴリズム全体が変更されます。クール。 – Servy

0

まあ主な問題はここにある:

foreach (Control control in controlsWithChildren) 
{ 
    return FindFirstControlOfType<T>(control, true); 
} 

あなたは戻っです子どもがいる最初の子を再帰的に検索した結果、その検索が成功したかどうかは関係ありません。幅優先探索は、広く議論トピックであるが、キューの使用に帰着:

Queue<Control> controlsWithChildren = new Queue<Control>(); 

および(通常は)ループではなく再帰。

関連する問題