【问题标题】:Finding controls that use a certain interface in ASP.NET在 ASP.NET 中查找使用特定接口的控件
【发布时间】:2010-09-06 22:01:22
【问题描述】:

与这个玩得很开心,虽然我觉得我错过了一些明显的东西。我有一个继承自System.Web.UI.WebControls.Button 的控件,然后实现我设置的接口。所以想想……

public class Button : System.Web.UI.WebControls.Button, IMyButtonInterface { ... }

在页面的代码隐藏中,我想从 ASPX 中找到此按钮的所有实例。因为我真的不知道 type 将是什么,只知道它实现的 interface,这就是我在循环控制树时所要做的一切。问题是,我从来不需要确定一个对象是否使用接口而不是只测试它的类型。 如何遍历控制树并以干净的方式拉出任何实现IMyButtonInterface 的内容(Linq 可以)?

再一次,知道这很明显,但刚刚开始大量使用接口,我似乎无法集中我的谷歌结果来弄清楚:)

编辑: GetType() 返回实际的类,但不返回接口,所以我无法对此进行测试(例如,它会返回“MyNamespace.Button”而不是“IMyButtonInterface”)。在尝试在递归函数中使用“as”或“is”时,type 参数甚至无法在函数中得到识别!这很奇怪。所以

if(ctrl.GetType() == typeToFind) //ok

if(ctrl is typeToFind) //typeToFind isn't recognized! eh?

这件事肯定让我摸不着头脑。

【问题讨论】:

    标签: c# asp.net


    【解决方案1】:

    Longhorn213 几乎有正确答案,但正如 Sean Chambers 和 bdukes 所说,您应该使用

    ctrl is IInterfaceToFind
    

    而不是

    ctrl.GetType() == aTypeVariable  
    

    原因是,如果你使用.GetType(),你会得到一个对象的真实类型,不一定是它在继承/接口实现链中也可以转换成的类型。此外,.GetType() 永远不会返回抽象类型/接口,因为您无法新建抽象类型或接口。 GetType() 仅返回具体类型。

    这不起作用的原因

    if(ctrl is typeToFind)  
    

    是因为变量typeToFind 的类型实际上是System.RuntimeType,而不是您为其设置值的类型。例如,如果您将字符串的值设置为“foo”,则其类型仍然是字符串而不是“foo”。我希望这是有道理的。使用类型时很容易混淆。与他们合作时,我一直很困惑。

    关于 longhorn213 的回答,最重要的一点是 您必须使用递归,否则您可能会错过页面上的某些控件。

    虽然我们在这里有一个可行的解决方案,但我也很想看看是否有更简洁的方法来使用 LINQ 来做到这一点。

    【讨论】:

    • 只有一个类型时,您可以在这种特殊情况下使用 IsAssignableFrom。
    【解决方案2】:

    您可以在界面上搜索。如果控件具有子控件(即按钮位于面板中),这也会使用递归。

    private List<Control> FindControlsByType(ControlCollection controls, Type typeToFind)
    {
        List<Control> foundList = new List<Control>();
    
        foreach (Control ctrl in this.Page.Controls)
        {
            if (ctrl.GetType() == typeToFind)
            {
                // Do whatever with interface
                foundList.Add(ctrl);
            }
    
            // Check if the Control has Child Controls and use Recursion
            // to keep checking them
            if (ctrl.HasControls())
            {
                // Call Function to 
                List<Control> childList = FindControlsByType(ctrl.Controls, typeToFind);
    
                foundList.AddRange(childList);
            }
        }
    
        return foundList;
    }
    
    // Pass it this way
    FindControlsByType(Page.Controls, typeof(IYourInterface));
    

    【讨论】:

      【解决方案3】:

      我将对 Longhorn213 的示例进行以下更改以稍微清理一下:

      private List<T> FindControlsByType<T>(ControlCollection controls )
      {
          List<T> foundList = new List<T>();
      
          foreach (Control ctrl in this.Page.Controls)
          {
              if (ctrl as T != null )
              {
                  // Do whatever with interface
                  foundList.Add(ctrl as T);
              }
      
              // Check if the Control has Child Controls and use Recursion
              // to keep checking them
              if (ctrl.HasControls())
              {
                  // Call Function to 
                  List<T> childList = FindControlsByType<T>( ctrl.Controls );
      
                  foundList.AddRange( childList );
              }
          }
      
          return foundList;
      }
      
      // Pass it this way
      FindControlsByType<IYourInterface>( Page.Controls );
      

      通过这种方式,您可以返回不需要其他类型转换即可使用的所需类型的对象列表。我还对其他人指出的“as”运算符进行了必要的更改。

      【讨论】:

        【解决方案4】:

        接口足够接近类型,感觉应该差不多。我会使用as operator

        foreach (Control c in this.Page.Controls) {
            IMyButtonInterface myButton = c as IMyButtonInterface;
            if (myButton != null) {
                // do something
            }
        }
        

        您也可以根据需要使用is operator 进行测试。

        if (c is IMyButtonInterface) {
            ...
        }
        

        【讨论】:

          【解决方案5】:

          “is”运算符会起作用吗?

          if (myControl is ISomeInterface)
          {
            // do something
          }
          

          【讨论】:

            【解决方案6】:

            如果你要对它做一些工作,如果它属于那种类型,那么我会使用 TryCast。

            Dim c as IInterface = TryCast(obj, IInterface)
            If c IsNot Nothing
                'do work
            End if
            

            【讨论】:

              【解决方案7】:

              你总是可以只使用 as cast:

              c as IMyButtonInterface;
              
              if (c != null)
              {
                 // c is an IMyButtonInterface
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2011-10-04
                • 1970-01-01
                • 1970-01-01
                • 2011-05-20
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-05-11
                相关资源
                最近更新 更多