7

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

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

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

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

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

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

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

肯定会在这个问题上挠头。

4

7 回答 7

7

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

ctrl is IInterfaceToFind

代替

ctrl.GetType() == aTypeVariable  

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

这不起作用的原因

if(ctrl is typeToFind)  

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

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

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

于 2008-08-26T17:50:51.637 回答
5

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

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));
于 2008-08-26T17:19:43.363 回答
4

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

于 2008-08-26T18:32:53.047 回答
1

接口与它应该感觉差不多的类型足够接近。我会使用as 运算符

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

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

if (c is IMyButtonInterface) {
    ...
}
于 2008-08-26T17:18:04.443 回答
1

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

if (myControl is ISomeInterface)
{
  // do something
}
于 2008-08-26T17:18:16.707 回答
0

如果您打算在它属于那种类型的情况下对其进行一些工作,那么我会使用 TryCast。

Dim c as IInterface = TryCast(obj, IInterface)
If c IsNot Nothing
    'do work
End if
于 2008-08-26T17:21:54.280 回答
0

你总是可以只使用 as cast:

c as IMyButtonInterface;

if (c != null)
{
   // c is an IMyButtonInterface
}
于 2008-08-26T17:49:27.660 回答