Когда следует использовать информацию о типе во время выполнения?

StackOverflow https://stackoverflow.com/questions/1520466

Вопрос

Если у меня есть различные подклассы чего-либо и алгоритм, который работает с экземплярами этих подклассов, и если поведение алгоритма немного меняется в зависимости от того, к какому конкретному подклассу относится экземпляр, то наиболее обычным объектно-ориентированным способом сделать это является использование виртуальных методов.

Например, если подклассы являются узлами DOM, и если алгоритм заключается в вставке дочернего узла, этот алгоритм отличается в зависимости от того, является ли родительский узел элементом DOM (который может иметь дочерние элементы) или текстом DOM (который не может):и вот этот insertChildren метод может быть виртуальным (или абстрактным) в DomNode базовый класс, и реализован по-разному в каждом из DomElement и DomText подклассы.

Другая возможность заключается в том, чтобы предоставить экземплярам общее свойство, значение которого можно прочитать:например, алгоритм может считывать nodeType собственность компании DomNode базовый класс;или, в качестве другого примера, у вас могут быть разные типы (подклассы) сетевых пакетов, которые совместно используют общий заголовок пакета, и вы можете прочитать заголовок пакета, чтобы увидеть, к какому типу относится данный пакет.

Я не часто использовал информацию о типе времени выполнения, в том числе:

  • Тот Самый is и as ключевые слова в C#
  • Понижающий коэффициент
  • Объект.Метод GetType в dot net
  • Тот Самый typeid оператор в C ++

Когда я добавляю новый алгоритм, который зависит от типа подкласса, я обычно добавляю новый виртуальный метод в иерархию классов.

Мой вопрос в том, когда целесообразно использовать информацию о типе времени выполнения вместо виртуальных функций?

Это было полезно?

Решение

Когда нет другого выхода.Виртуальные методы всегда предпочтительнее, но иногда их просто невозможно использовать.Есть пара причин, по которым это может произойти, но наиболее распространенной из них является то, что у вас нет исходного кода классов, с которыми вы хотите работать, или вы не можете их изменить.Это часто случается, когда вы работаете с устаревшей системой или коммерческой библиотекой с закрытым исходным кодом.

В .NET также может случиться так, что вам придется загружать новые сборки "на лету", например плагины, и у вас, как правило, нет базовых классов, но приходится использовать что-то вроде утиного ввода.

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

В C ++, среди некоторых других неясных случаев (которые в основном связаны с некачественным выбором дизайна), RTTI - это способ реализации так называемых несколько методов.

Эти конструкции ("is" и "as") очень знакомы разработчикам Delphi, поскольку обработчики событий обычно низводят объекты к общему предку.Например, событие OnClick передает единственный отправитель аргумента:TObject независимо от типа объекта, будь то TButton, TListBox или любой другой.Если вы хотите узнать что-то больше об этом объекте, вы должны получить к нему доступ через "as", но чтобы избежать исключения, вы можете проверить его с помощью "is" раньше.Это сокращение позволяет привязывать объекты и методы к типу проектирования, что было бы невозможно при строгой проверке типа класса.Представьте, что вы хотите сделать то же самое, если пользователь нажимает кнопку или ListBox, но если они предоставляют нам разные прототипы функций, привязать их к одной и той же процедуре может оказаться невозможным.

В более общем случае объект может вызывать функцию, которая уведомляет, например, о том, что объект изменился.Но заранее это оставляет адресату возможность узнать его "лично" (через "как есть"), но не обязательно.Он делает это, передавая self в качестве наиболее общего предка всех объектов (TObject в случае Delphi).

dynamic_cast (динамическая передача)<>, если я правильно помню, зависит от RTTI.Некоторые неясные внешние интерфейсы могут также полагаться на RTTI, когда объект передается через указатель void (по любой причине это может случиться).

Тем не менее, я не видел typeof() в дикой природе за 10 лет работы по обслуживанию pro C ++.(К счастью.)

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

Пункт 3.Специализированные Универсальные алгоритмы Использование проверки типов во время выполнения

Вы можете легко повторно использовать дженерики, просто указав новые параметры типа.Новый экземпляр с параметрами нового типа означает новый тип, имеющий аналогичную функциональность.

Все это здорово, потому что вы пишете меньше кода.Однако иногда быть более общим означает не использовать преимущества более конкретного, но явно превосходящего алгоритма.Правила языка C# учитывают это.Все, что вам нужно, это признать что ваш алгоритм может быть более эффективным, когда параметры типа обладают большими возможностями, а затем написать этот конкретный код.Кроме того, создание второго универсального типа, который задает другие ограничения , не всегда работает.Универсальный Создание экземпляров основано на типе объекта во время компиляции, а не на типе среды выполнения.Если вы не сможете принять это во внимание, вы можете упустить возможную эффективность.

Например, предположим, что вы пишете класс, который предоставляет перечисление в обратном порядке для последовательности элементов, представленных через IEnumerable<T>.Чтобы перечислить его в обратном порядке, вы можете повторить его и скопировать элементы в промежуточную коллекцию с доступом к индексатору, например List<T> , а затем перечислить эту коллекцию, используя доступ к индексатору в обратном порядке.Но если ваш исходный IEnumerable является IList, почему бы не воспользоваться этим и не предоставить более эффективный способ (без копирования в промежуточную коллекцию) повторять элементы в обратном направлении.Таким образом, в принципе, это нечто особенное, чем мы можем воспользоваться, но при этом обеспечивающее то же поведение (повторение последовательности в обратном направлении).

Но в целом вам следует внимательно отнестись к проверке типов во время выполнения и убедиться, что это не нарушает принцип подстановки Лискова.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top