在 ASP.NET 中查找使用特定接口的控件
Posted
技术标签:
【中文标题】在 ASP.NET 中查找使用特定接口的控件【英文标题】:Finding controls that use a certain interface in 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?
这件事肯定让我摸不着头脑。
【问题讨论】:
【参考方案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
【讨论】:
以上是关于在 ASP.NET 中查找使用特定接口的控件的主要内容,如果未能解决你的问题,请参考以下文章
使用 jQuery 启用/禁用特定“验证组”中的 asp.net 验证控件?