在这段时间里度过了愉快的时光,尽管我觉得我缺少明显的东西。我有一个从System.Web.UI.WebControls.Button继承的控件,然后实现了我设置的接口。所以想...
1
| public class Button : System.Web.UI.WebControls.Button, IMyButtonInterface { ... } |
在页面后面的代码中,我想从ASPX中找到此按钮的所有实例。因为我真的不知道类型是什么,所以只知道它实现的接口,这就是我遍历控制树时要做的所有事情。事实是,我不必确定对象是否使用接口,而不必测试其类型。我怎样才能遍历控制树并以干净的方式提取实现IMyButtonInterface的任何东西(Linq会很好)?
同样,知道这很明显,但是现在刚开始大量使用界面,我似乎无法集中我的Google结果来弄清楚它:)
编辑:GetType()返回实际的类,但不返回接口,因此我无法对此进行测试(例如,它将返回" MyNamespace.Button"而不是" IMyButtonInterface")。在递归函数中尝试使用" as"或" is"时,type参数甚至在函数中都未被识别!这很奇怪。所以
1 2 3
| if(ctrl.GetType() == typeToFind) //ok
if(ctrl is typeToFind) //typeToFind isn't recognized! eh? |
绝对是我的头。
Longhorn213几乎是正确的答案,但是正如肖恩·钱伯斯(sean Chambers)和bdukes所说,应该使用
1
| ctrl is IInterfaceToFind |
而不是
1
| ctrl.GetType() == aTypeVariable |
之所以这样,是因为如果使用.GetType(),您将获得对象的真实类型,不一定是它在继承/接口实现链中也可以转换为的对象。同样,.GetType()将永远不会返回抽象类型/接口,因为您无法新建抽象类型或接口。 GetType()仅返回具体类型。
不起作用的原因
是因为变量typeToFind的类型实际上是System.RuntimeType,而不是您将其值设置为的类型。例如,如果将字符串的值设置为" foo",则其类型仍然是字符串而不是" foo"。我希望这是有道理的。使用类型时很容易感到困惑。与他们一起工作时,我很困惑。
关于longhorn213的答案,最重要的一点是您必须使用递归,否则您可能会错过页面上的某些控件。
尽管这里有一个可行的解决方案,但我也很想看看LINQ是否有更简洁的方法。
您可以只在界面上搜索。如果控件具有子控件,即按钮位于面板中,则也将使用递归。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| 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)); |
我将对Longhorn213的示例进行以下更改以对其进行清理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| 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"运算符进行了必要的更改。
"运算符"是否可以工作?
1 2 3 4
| if (myControl is ISomeInterface)
{
// do something
} |
接口足够接近应该具有相同感觉的类型。我将使用as运算符。
1 2 3 4 5 6
| foreach (Control c in this.Page.Controls) {
IMyButtonInterface myButton = c as IMyButtonInterface;
if (myButton != null) {
// do something
}
} |
您还可以根据需要使用is运算符进行测试。
1 2 3
| if (c is IMyButtonInterface) {
...
} |
您总是可以使用as强制转换:
1 2 3 4 5 6
| c as IMyButtonInterface;
if (c != null)
{
// c is an IMyButtonInterface
} |
如果您要对该类型进行一些工作,那么TryCast是我要使用的。
1 2 3 4
| Dim c as IInterface = TryCast(obj, IInterface)
If c IsNot Nothing
'do work
End if |