Поиск элементов управления, использующих определенный интерфейс в 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?

Определенно почесываю голову над этим.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
7
0
2 321
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Интерфейсы достаточно близки к типам, поэтому ощущения должны быть примерно такими же. Я бы использовал как оператор.

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.

Вы можете использовать IsAssignableFrom для этого конкретного случая, когда у вас есть только тип.

Jan Jongboom 08.09.2009 19:24

Я бы внес следующие изменения в пример 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», на который указали другие.

Другие вопросы по теме