在ASP.NET中查找使用特定接口的控件

时间:2020-03-05 18:43:26  来源:igfitidea点击:

尽管我觉得我错过了一些明显的事情,但在这段时间过得很愉快。我有一个继承自System.Web.UI.WebControls.Button的控件,然后实现了我设置的接口。所以想...

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

在页面的代码背后,我想从ASPX中找到此按钮的所有实例。因为我真的不知道类型是什么,所以只知道它实现的接口,这就是我遍历控制树时要做的所有事情。事实是,我不必确定对象是否使用接口,而不必测试其类型。我该如何遍历控制树并以干净的方式提取实现" IMyButtonInterface"的任何内容(Linq会很好)?

再说一遍,知道这很明显,但是现在刚开始大量使用接口,我似乎无法集中我的Google结果来弄清楚它:)

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

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

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

绝对在这上面挠头。

解决方案

回答

接口足够接近应该具有相同感觉的类型。我会用as运算符。

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

我们还可以根据需要使用is运算符进行测试。

if (c is IMyButtonInterface) {
    ...
}

回答

"是"操作员会工作吗?

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

回答

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

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));

回答

如果我们要对该类型进行一些工作,那么TryCast是我要使用的。

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

回答

我们总是可以只使用as强制转换:

c as IMyButtonInterface;

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

回答

Longhorn213几乎是正确的答案,但是正如肖恩·钱伯斯(Sean Chambers)和bdukes所说,我们应该使用

ctrl is IInterfaceToFind

代替

ctrl.GetType() == aTypeVariable

原因是,如果使用.GetType(),我们将获得对象的真实类型,不一定是在继承/接口实现链中也可以将其强制转换为对象的类型。另外,.GetType()将永远不会返回抽象类型/接口,因为我们无法创建抽象类型或者接口。 GetType()仅返回具体类型。

这不起作用的原因

if(ctrl is typeToFind)

是因为变量" typeToFind"的类型实际上是" System.RuntimeType",而不是我们将其值设置为的类型。例如,如果将字符串的值设置为"foo",则其类型仍为字符串,而不是"foo"。我希望这是有道理的。使用类型时很容易感到困惑。与他们一起工作时,我总是很困惑。

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

尽管这里有一个可行的解决方案,但我也很想看看LINQ是否有更简洁的方法。

回答

我将对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"运算符进行了必要的更改。