Раннее и позднее связывание
Я пытаюсь разобраться, когда раннее / позднее связывание происходит в C#.
Не виртуальные методы всегда связаны рано. Виртуальные методы всегда имеют позднюю привязку: компилятор вставляет дополнительный код, чтобы разрешить фактический метод для привязки во время выполнения, и проверяет безопасность типов. Так что подтип полиморфизма использует позднее связывание.
Вызов методов с использованием отражения является примером позднего связывания. Мы пишем код для достижения этой цели, а не для компилятора. (Например, вызов COM-компонентов.)
VB.NET поддерживает неявное позднее связывание, когда Option Strict выключен. Объект имеет позднюю привязку, когда ему назначается переменная, объявленная как тип Object. Компилятор VB вставляет код для привязки к нужному методу во время выполнения и для перехвата недопустимых вызовов. C# не поддерживает эту функцию.
Я иду в правильном направлении?
Как насчет вызова делегатов и вызова метода через ссылку на интерфейс? Это раннее или позднее связывание?
7 ответов
Все рано связывается в C#, если вы не пройдете через интерфейс Reflection.
Ранняя привязка просто означает, что целевой метод найден во время компиляции, и создан код, который будет вызывать это. Является ли он виртуальным или нет (то есть, есть дополнительный шаг, чтобы найти его во время разговора, не имеет значения). Если метод не существует, компилятор не сможет скомпилировать код.
Поздняя граница означает, что целевой метод ищется во время выполнения. Часто текстовое имя метода используется для поиска. Если метод не существует, взрыв. Программа завершится сбоем или перейдет к какой-либо схеме обработки исключений во время выполнения.
Большинство языков сценариев используют позднюю привязку, а скомпилированные языки используют раннюю привязку.
C# (до версии 4) не запаздывает; однако они могут использовать API отражения для этого. Этот API компилируется в код, который ищет имена функций, просматривая сборки во время выполнения. VB может поздно связываться, если Option Strict выключен.
Связывание обычно влияет на производительность. Поскольку поздняя привязка требует поиска во время выполнения, обычно это означает, что вызовы методов медленнее, чем вызовы методов с ранней привязкой.
Для нормальной функции компилятор может определить ее числовое местоположение в памяти. Затем, когда функция вызывается, она может сгенерировать инструкцию для вызова функции по этому адресу.
Для объекта с любыми виртуальными методами компилятор сгенерирует v-таблицу. По сути, это массив, содержащий адреса виртуальных методов. Каждый объект, имеющий виртуальный метод, будет содержать скрытый элемент, сгенерированный компилятором, который является адресом v-таблицы. Когда вызывается виртуальная функция, компилятор определяет, какова позиция соответствующего метода в v-таблице. Затем он сгенерирует код для просмотра v-таблицы объектов и вызова виртуального метода в этой позиции.
Итак, поиск для виртуальной функции происходит. Это сильно оптимизировано, поэтому это будет происходить очень быстро во время выполнения.
Рано связаны
- Компилятор может определить, где будет вызвана функция во время компиляции.
- Компилятор может рано (до запуска кода любой программы) гарантировать, что функция будет существовать и будет вызываться во время выполнения.
- Компилятор гарантирует, что функция принимает правильное количество аргументов и что они имеют правильный тип. Он также проверяет, что возвращаемое значение имеет правильный тип.
Позднее связывание
- Поиск займет больше времени, потому что это не простой расчет смещения, обычно необходимо выполнить сравнение текста.
- Целевая функция может не существовать.
- Функция назначения может не принимать переданные ей аргументы и может иметь возвращаемое значение неправильного типа.
- В некоторых реализациях целевой метод может фактически меняться во время выполнения. Таким образом, поиск может выполнять другую функцию. Я думаю, что это происходит на языке Ruby, вы можете определить новый метод для объекта во время работы программы. Позднее связывание позволяет вызовам функций начинать вызывать новое переопределение для метода вместо вызова существующего базового метода.
C# 3 использует раннее связывание.
C# 4 добавляет позднее связывание с dynamic
ключевое слово. См . Запись в блоге Криса Берроу по этому вопросу для получения подробной информации.
Что касается виртуальных и не виртуальных методов, это другая проблема. Если я позвоню string.ToString()
код C# привязан к виртуальному object.ToString()
метод. Код вызывающей стороны не изменяется в зависимости от типа объекта. Скорее, виртуальные методы вызываются через таблицу указателей функций. Экземпляр объекта ссылается на таблицу объекта, указывающую на его ToString()
метод. Экземпляр строки имеет свою таблицу виртуальных методов, указывающую на ToString()
метод. Да, это полиморфизм. но еще не поздно связать.
В большинстве случаев раннее связывание - это то, что мы делаем ежедневно. Например, если у нас есть Employee
класс, доступный во время компиляции, мы просто создаем экземпляр этого класса и вызываем любые члены экземпляра. Это раннее связывание.
//Early Binding
**Employee** employeeObject = new **Employee**();
employeeObject.CalculateSalary();
С другой стороны, если у вас нет знаний о классе во время компиляции, тогда единственный способ - это позднее связывание с использованием рефлексии. Я наткнулся на отличное видео, объясняющее эти понятия - вот ссылка.
Раннее связывание
Само имя описывает, что компилятор знает, что это за объект, какие методы и свойства он содержит. Как только вы объявите объект, .NET Intellisense заполняет его методы и свойства нажатием кнопки "точка".
Типичные примеры:
ComboBox cboItems;
ListBox lstItems; В приведенных выше примерах, если мы введем cboItem и поставим точку, за которой следует точка, она автоматически заполнит все методы, события и свойства поля со списком, потому что компилятор уже знает, что это поле со списком.
Позднее связывание
Само имя описывает, что компилятор не знает, что это за объект, какие все методы и свойства он содержит. Вы должны объявить его как объект, позже вам нужно получить тип объекта, методы, которые в нем хранятся. Все будет известно во время выполнения.
Типичные примеры:
Объектные объекты;
objItems = CreateObject ("DLL или имя сборки"); Здесь во время компиляции тип объектов не определяется. Мы создаем объект dll и присваиваем его объектам, поэтому все определяется во время выполнения.
Раннее связывание против позднего связывания
Теперь входя в картину...
Приложение будет работать быстрее при раннем связывании, так как здесь не выполняется упаковка или распаковка.
Проще написать код в ранней привязке, так как intellisense будет заполняться автоматически
Минимальные ошибки в раннем связывании, так как синтаксис проверяется во время самой компиляции.
Позднее связывание будет поддерживаться во всех версиях, так как все решается во время выполнения.
Минимальное влияние кода в будущих улучшениях, если используется Позднее связывание.
Производительность будет кодом в начале связывания. У обоих есть свои достоинства и недостатки, и разработчик решает выбрать соответствующую привязку в зависимости от сценария.
Это очень старая запись, но я хотел добавить к ней больше информации. Позднее связывание используется, когда вы не хотите создавать экземпляр объекта во время компиляции. В C#
ты используешь Activator
вызвать объект привязки во время выполнения.
Проще говоря, раннее связывание происходит во время компиляции, и компилятор знает о типе и всех его членах, а позднее связывание происходит во время выполнения, компилятор ничего не знает о типе и его членах. Я наткнулся на отличное видео на YouTube, которое объясняет эти концепции.
http://www.youtube.com/watch?v=s0eIgl5iqqQ&list=PLAC325451207E3105&index=55&feature=plpp_video
Эта статья представляет собой руководство по созданию компонента.net, его использованию в проекте Vb6 во время выполнения с использованием позднего связывания, прикрепления его событий и получения обратного вызова.
http://www.codeproject.com/KB/cs/csapivb6callback2.aspx
Эта статья представляет собой руководство по созданию компонента.NET и его использованию в проекте VB6. Есть много примеров по этой проблеме, так почему я написал новый? По моему скромному мнению, в других статьях недостающая часть заключается в прикреплении своего события во время выполнения. Поэтому в этой статье мы создадим компонент.NET, отметим его как видимый COM-компонент, используем его во время выполнения в VB6 и подключаем к его событиям.
https://www.codeproject.com/Articles/37127/Internet-Explorer-Late-Binding-Automation
Большинству разработчиков часто требуется автоматизация Internet Explorer, что в основном означает открытие браузера, заполнение некоторых форм и размещение данных программным способом.
Наиболее распространенным подходом является использование shdocvw.dll (элемент управления веб-браузера Microsoft) и Mshtml.dll (компонент синтаксического анализа и рендеринга HTML) или Microsoft.Mshtml.dll, который на самом деле является оболочкой.NET для Mshtml.dll. Вы можете получить больше информации об Internet Explorer - О браузере здесь.
Если вы выберете вышеуказанный метод и библиотеки DLL, давайте посмотрим на некоторые проблемы, с которыми вам, возможно, придется столкнуться:
Вы должны распространять эти библиотеки DLL, потому что ваш проект будет зависеть от этих библиотек DLL, и это серьезная проблема, если вы не можете правильно их развернуть. Просто сделайте поиск в Google по поводу проблем с распределением shdocvw и mshtml.dll, и вы поймете, о чем я говорю. Вы должны развернуть 8 МБ Microsoft.mshtml.dll, потому что эта DLL не является частью.NET Framework. В этом случае нам нужно использовать метод позднего связывания. Написание собственных оболочек для вышеупомянутых DLL. И, конечно же, мы сделаем это, так как это более полезно, чем использование этих DLL. Например, нам не нужно проверять, завершена ли операция загрузки документа, потому что IEHelper сделает это за нас.