Раннее и позднее связывание - PullRequest
76 голосов
/ 27 января 2009

Я пытаюсь разобраться, когда в C # происходит раннее / позднее связывание.

Не виртуальные методы всегда имеют раннюю привязку. Виртуальные методы всегда имеют позднюю привязку: компилятор вставляет дополнительный код, чтобы разрешить фактический метод для привязки во время выполнения, и проверяет безопасность типов. Таким образом, полиморфизм подтипа использует позднее связывание.

Вызов методов с использованием отражения является примером позднего связывания. Мы пишем код для достижения этого в отличие от компилятора. (Например, вызов COM-компонентов.)

VB.NET поддерживает неявное позднее связывание, когда Option Strict выключен. Объект имеет позднюю привязку, когда он назначается переменной, объявленной как тип Object. Компилятор VB вставляет код для привязки к нужному методу во время выполнения и для перехвата недопустимых вызовов. C # не поддерживает эту функцию.

Я иду в правильном направлении?

Как насчет вызова делегатов и вызова метода через ссылку на интерфейс? Это раннее или позднее связывание?

Ответы [ 7 ]

95 голосов
/ 27 января 2009

Все рано связывается в C #, если вы не пройдете через интерфейс Reflection.

Раннее связывание означает, что целевой метод найден во время компиляции, и создан код, который будет вызывать это. Является ли он виртуальным или нет (то есть, есть дополнительный шаг, чтобы найти его во время разговора, не имеет значения). Если метод не существует, компилятор не сможет скомпилировать код.

Поздняя граница означает, что целевой метод ищется во время выполнения. Часто текстовое имя метода используется для его поиска. Если метод не существует, взрыв. Во время выполнения программа завершится сбоем или перейдет к какой-либо схеме обработки исключений.

Большинство языков сценариев используют позднюю привязку, а скомпилированные языки используют раннюю привязку.

C # (до версии 4) не выполняет позднюю привязку; однако они могут использовать API отражения для этого. Этот API компилируется в код, который ищет имена функций, просматривая сборки во время выполнения. VB может выполнить позднее связывание, если Option Strict выключен.

Связывание обычно влияет на производительность. Поскольку позднее связывание требует поиска во время выполнения, обычно это означает, что вызовы методов медленнее, чем вызовы методов с ранним связыванием.


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

Для объекта, у которого есть какие-либо виртуальные методы, компилятор сгенерирует v-таблицу. По сути, это массив, содержащий адреса виртуальных методов. Каждый объект, имеющий виртуальный метод, будет содержать скрытый элемент, сгенерированный компилятором, который является адресом v-таблицы. Когда вызывается виртуальная функция, компилятор определяет, какова позиция соответствующего метода в v-таблице. Затем он сгенерирует код для просмотра v-таблицы объектов и вызова виртуального метода в этой позиции.

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

Ранняя оценка

  • Компилятор может определить, где будет вызвана функция во время компиляции.
  • Компилятор может рано (до запуска кода любой программы) гарантировать, что функция будет существовать и будет вызываться во время выполнения.
  • Компилятор гарантирует, что функция принимает правильное количество аргументов и что они имеют правильный тип. Он также проверяет, что возвращаемое значение имеет правильный тип.

Поздний переплет

  • Поиск займет больше времени, потому что это не простое вычисление смещения, обычно необходимо выполнить сравнение текста.
  • Целевая функция может не существовать.
  • Целевая функция может не принимать переданные ей аргументы и может иметь возвращаемое значение неправильного типа.
  • В некоторых реализациях целевой метод может фактически меняться во время выполнения. Таким образом, поиск может выполнять другую функцию. Я думаю, что это происходит на языке Ruby, вы можете определить новый метод для объекта во время работы программы. Позднее связывание позволяет вызовам функций начинать вызывать новое переопределение для метода вместо вызова существующего базового метода.
16 голосов
/ 27 января 2009

C # 3 использует раннее связывание.

C # 4 добавляет позднюю привязку с ключевым словом dynamic. Подробнее см. запись в блоге Криса Берроу .

Что касается виртуальных и не виртуальных методов, то это другая проблема. Если я вызываю string.ToString(), код C # привязывается к виртуальному object.ToString() методу. Код вызывающей стороны не изменяется в зависимости от типа объекта. Скорее, виртуальные методы вызываются через таблицу указателей функций. Экземпляр объекта ссылается на таблицу объекта, указывающую на метод ToString(). Экземпляр строки имеет свою таблицу виртуальных методов, указывающую на метод ToString(). Да, это полиморфизм. но еще не поздно связать.

5 голосов
/ 09 июля 2012

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

//Early Binding
**Employee** employeeObject = new **Employee**();
employeeObject.CalculateSalary();

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

3 голосов
/ 25 мая 2017

Раннее связывание

Само имя описывает, что компилятор знает, что это за объект, какие у него все методы и свойства. Как только вы объявите объект, .NET Intellisense заполнит его методы и свойства нажатием кнопки с точкой.

Типичные примеры:

ComboBox cboItems;

ListBox lstItems; В приведенных выше примерах, если мы введем cboItem и поставим точку, за которой следует точка, она автоматически заполнит все методы, события и свойства поля со списком, поскольку компилятор уже знает, что это поле со списком.

Позднее связывание

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

Типичные примеры:

Объект objItems;

objItems = CreateObject ("DLL или имя сборки"); Здесь во время компиляции тип объектов не определяется. Мы создаем объект dll и присваиваем его объектам, поэтому все определяется во время выполнения.

Раннее связывание против позднего связывания

Теперь входя в картину ...

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

Проще написать код в ранней привязке, так как intellisense будет заполняться автоматически

Минимальные ошибки в раннем связывании, поскольку синтаксис проверяется во время самой компиляции.

Позднее связывание будет поддерживаться во всех видах версий, поскольку все решается во время выполнения.

Минимальное влияние кода в будущих улучшениях, если используется Позднее связывание.

Производительность будет кодом в начале связывания. У обоих есть свои достоинства и недостатки, и разработчик решает выбрать соответствующую привязку в зависимости от сценария.

3 голосов
/ 27 сентября 2012

Это очень старая запись, но я хотел добавить к ней больше информации. Позднее связывание используется, когда вы не хотите создавать экземпляр объекта во время компиляции. В C# вы используете Activator для вызова объекта связывания во время выполнения.

2 голосов
/ 04 сентября 2012

Проще говоря, раннее связывание происходит во время компиляции, и компилятор знает о типе и всех его членах, а позднее связывание происходит во время выполнения, компилятор ничего не знает о типе и его членах. Я наткнулся на отличное видео на YouTube, которое объясняет эти концепции.

http://www.youtube.com/watch?v=s0eIgl5iqqQ&list=PLAC325451207E3105&index=55&feature=plpp_video

http://www.youtube.com/playlist?list=PLAC325451207E3105

1 голос
/ 26 апреля 2010

Эта статья представляет собой руководство по созданию компонента .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 сделает это за нас.

...