Поиск элементов управления, которые используют определенный интерфейс в ASP.NET
Я провожу время с этим, хотя я чувствую, что упускаю что-то очевидное. У меня есть элемент управления, который наследует от 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?
Определенно почесал голову над этим.
7 ответов
Longhorn213 почти имеет правильный ответ, но, как говорят Шон Чемберс и bdukes, вы должны использовать
ctrl is IInterfaceToFind
вместо
ctrl.GetType() == aTypeVariable
Причина в том, что если вы используете .GetType()
вы получите истинный тип объекта, не обязательно тот, к которому он также может быть приведен в цепочке реализации наследования / интерфейса. Также, .GetType()
никогда не вернет абстрактный тип / интерфейс, так как вы не можете создать новый абстрактный тип или интерфейс. GetType()
возвращает только конкретные типы.
Причина, по которой это не работает
if(ctrl is typeToFind)
Это потому, что тип переменной typeToFind
на самом деле System.RuntimeType
, а не тип, для которого вы установили его значение. Пример, если вы установите значение строки в "foo
msgstr "его тип по-прежнему не является строкой"foo
"Я надеюсь, что это имеет смысл. Очень легко запутаться при работе с типами. Я хронически запутался при работе с ними".
Самое важное, что следует отметить в ответе longhorn213, это то, что вам нужно использовать рекурсию, иначе вы можете пропустить некоторые элементы управления на странице.
Хотя у нас есть рабочее решение, я бы тоже хотел узнать, есть ли более лаконичный способ сделать это с помощью LINQ.
Вы можете просто искать на интерфейсе. Это также использует рекурсию, если элемент управления имеет дочерние элементы управления, т.е. кнопка находится на панели.
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, чтобы немного это исправить:
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 );
Таким образом, вы получите список объектов нужного типа, которые не требуют использования другого приведения. Я также внес необходимые изменения в оператор "как", на который указали другие.
Будет ли работать оператор "is"?
if (myControl is ISomeInterface)
{
// do something
}
Интерфейсы достаточно близки к типам, что должно восприниматься примерно одинаково. Я бы использовал оператор как.
foreach (Control c in this.Page.Controls) {
IMyButtonInterface myButton = c as IMyButtonInterface;
if (myButton != null) {
// do something
}
}
Вы также можете проверить с помощью оператора is, в зависимости от ваших потребностей.
if (c is IMyButtonInterface) {
...
}
Если вы собираетесь поработать над этим, если он такого типа, то я бы использовал TryCast.
Dim c as IInterface = TryCast(obj, IInterface)
If c IsNot Nothing
'do work
End if
Вы всегда можете просто использовать as cast:
c as IMyButtonInterface;
if (c != null)
{
// c is an IMyButtonInterface
}