Провела время с этим чертовски хорошо, хотя я чувствую, что упускаю что-то очевидное. У меня есть элемент управления, который наследуется от 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?
Определенно почесываю голову над этим.





Интерфейсы достаточно близки к типам, поэтому ощущения должны быть примерно такими же. Я бы использовал как оператор.
foreach (Control c in this.Page.Controls) {
IMyButtonInterface myButton = c as IMyButtonInterface;
if (myButton != null) {
// do something
}
}
Вы также можете протестировать с помощью оператор, в зависимости от ваших потребностей.
if (c is IMyButtonInterface) {
...
}
Будет ли работать оператор "is"?
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 cast:
c as IMyButtonInterface;
if (c != null)
{
// c is an IMyButtonInterface
}
У Longhorn213 есть почти правильный ответ, но, как говорят Шон Чемберс и 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», на который указали другие.
Вы можете использовать IsAssignableFrom для этого конкретного случая, когда у вас есть только тип.