Преобразование типов объектов в Delphi

Хочу рассмотреть один дискуссионный вопрос связанный с преобразованием типов. Сначала краткое введение. В Delphi существует два оператора is и as, связанных с преобразованием типов, и способ преобразования типа с помощью функции с именем типа (класса).

Оператор is используется для проверки типа, если объект соответствует указанному типу или является его наследником, то оператор возвращает True. В случае если в переменной nil то оператор возвращает False.

Оператор as используется для преобразования типа. Если объект соответствует типу или наследнику, то он преобразуется, если нет то выдаётся исключение EInvalidCast. В случае если в переменной nil, то исключение не произойдёт, но, конечно, обратится к полям объекта не получится - будет другое исключение.

Существует второй способ преобразования типа переменной - просто оборачиваем её в функцию с именем нужного класса. В этом случае проверки на тип не происходит. Посмотреть различия в работе можно на следующем коде:

А вот и сам вопрос. Предположим мы делаем проверку на тип объекта и потом выполняем с ним какие-то действия. Какой вариант использовать предпочтительнее?

Некоторые моменты.

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

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

В рассматриваемом вопросе интересует именно читаемость и идиоматичность таких конструкций для Delphi. Есть некоторые за и против двух вариантов.

Вариант с функцией короче (меньше символов) и содержит на одну конструкцию меньше, что делает его проще.

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

С другой стороны, возможно, способ с функций больше подходит для преобразования простых типов, а для классов следует всегда использовать as. В документации при описании преобразования типов указано "For information about casting class and interface types, see "The as Operator" in Class References and Interface References (Delphi).". Впрочем, эта предложение, никак не указывает и не намекает на предпочтительность оператора as.

И ещё есть аспект надёжности, особенно в крупном проекте с участием большого количества разработчиков. В этом смысле преимущества у варианта с оператором as. Например, если часть "(Sender as TMaskEdit).Text" будет скопирована в любой другой контекст, можно быть уверенным что объект будет нужного типа или код упадёт с исключением. Если же применяется вариант "TMaskEdit(Sender).Text" то может возникнуть неопределённое поведение. Это похоже на один из доводов в пользу отказа от with.

Буду рад выслушать любые мысли по этому поводу.

Ссылки на документацию

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Преобразование типов объектов в Delphi: 3 комментария

  1. Если предварительно идет проверка is, то лучше не использовать преобразование as
    т.е. или
    if Sender is TMaskEdit then
    ShowMessage(TMaskEdit(Sender).Text);
    или
    ShowMessage((Sender as TMaskEdit).Text);
    Первый быстрее и не будет ексепшен вызываться (с интерфейсами тоже самое)

  2. IS и AS не работают в DLL, само в BPL. Я лично использую их везде где код будет работать только в Application. Удобно проверять когда присуствовать йерархия типов.

    1. Вероятно, is и as не работает в dll, так как не включена опция Build with runtame packages. Если в dll и в приложение подключается одна rtl, то эти конструкции должны работать.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *