Ранняя и поздняя привязка
Я пытаюсь разобраться, когда раннее/позднее связывание происходит на С#.
Не виртуальные методы всегда ранние. Виртуальные методы всегда ограничены: компилятор добавляет дополнительный код для разрешения фактического метода привязки во время выполнения и проверки безопасности типа. Таким образом, полиморфизм подтипа использует позднюю привязку.
Вызов методов с использованием отражения является примером позднего связывания. Мы пишем код для достижения этого, а не компилятора. (Например, вызов COM-компонентов.)
VB.NET поддерживает скрытое связывание, когда параметр Strict выключен. Объект опоздает, когда ему присваивается переменная, объявленная как тип Object. Компилятор VB вставляет код для привязки к правильному методу во время выполнения и для улавливания недействительных вызовов. С# не поддерживает эту функцию.
Я направляюсь в правильном направлении?
Как насчет вызова делегатов и вызова метода с помощью ссылки на интерфейс? Это раннее или позднее связывание?
Ответы
Ответ 1
Все ранние ограничения в С#, если вы не проходите через интерфейс Reflection.
Ранняя привязка просто означает, что целевой метод найден во время компиляции, и создается код, который будет вызывать это. Является ли его виртуальным или нет (что означает, что дополнительный шаг, чтобы найти его во время вызова, не имеет значения). Если метод не существует, компилятор не сможет скомпилировать код.
Поздняя привязка означает, что целевой метод просматривается во время выполнения. Часто текстовое имя метода используется для поиска. Если метода там нет, взломайте. Программа выйдет из строя или войдет в схему обработки исключений во время выполнения.
В большинстве языков script используется поздняя привязка, а скомпилированные языки используют раннее связывание.
С# (до версии 4) не опоздает; однако они могут использовать API отражения для этого. Этот API компилируется для кодирования, который ищет имена функций, выкапывая сборки во время выполнения. VB может опоздать, если параметр Strict отключен.
Связывание обычно влияет на производительность. Поскольку поздняя привязка требует поиска во время выполнения, обычно это означает, что вызовы метода медленнее, чем вызовы метода ранней привязки.
Для нормальной функции компилятор может определить числовое местоположение в памяти. Затем, когда функция вызывается, она может генерировать команду для вызова функции по этому адресу.
Для объекта, который имеет какие-либо виртуальные методы, компилятор будет генерировать v-таблицу. Это по существу массив, содержащий адреса виртуальных методов. Каждый объект, имеющий виртуальный метод, будет содержать скрытый элемент, сгенерированный компилятором, который является адресом v-таблицы. Когда вызывается виртуальная функция, компилятор будет определять, какая позиция имеет соответствующий метод в таблице v. Затем он сгенерирует код для поиска в v-таблице объектов и вызовет виртуальный метод в этой позиции.
Итак, есть поиск, который возникает для виртуальной функции. Это сильно оптимизировано, так что это произойдет очень быстро во время выполнения.
Ранняя граница
- Компилятор может работать там, где вызываемая функция будет во время компиляции.
- Компилятор может гарантировать раннее (до запуска любого из программного кода), что функция будет существовать и быть вызываемой во время выполнения.
- Компилятор гарантирует, что функция принимает правильное количество аргументов и что они имеют правильный тип. Он также проверяет, что возвращаемое значение имеет правильный тип.
Поздняя привязка
- Поиск займет больше времени, потому что это не простой расчет смещения, обычно есть текстовые сравнения.
- Целевая функция может не существовать.
- Целевая функция может не принимать переданные ей аргументы и может иметь возвращаемое значение неправильного типа.
- В некоторых реализациях целевой метод может фактически измениться во время выполнения. Таким образом, поиск может выполнять другую функцию. Я думаю, что это происходит на языке Ruby, вы можете определить новый метод для объекта во время работы программы. Late-binding позволяет вызвать вызовы функций для вызова нового переопределения для метода вместо вызова существующего базового метода.
Ответ 2
С# 3 использует раннее связывание.
С# 4 добавляет последнее связывание с ключевым словом dynamic
. Подробнее см. запись в блоге Chris Burrow по этому вопросу.
Что касается виртуальных и не виртуальных методов, это другая проблема. Если я вызываю string.ToString()
, код С# привязан к виртуальному методу object.ToString()
. Код вызывающего абонента не изменяется в зависимости от типа объекта. Скорее, виртуальные методы вызывают через таблицу указателей функций. Экземпляр объекта относится к таблице объектов, указывающей на него метод ToString()
. Экземпляр строки имеет таблицу виртуальных методов, указывающую на нее метод ToString()
. Да, это полиморфизм. но это не поздняя привязка.
Ответ 3
В большинстве случаев раннее связывание - это то, что мы делаем ежедневно. Например, если у нас есть класс Employee
, доступный во время компиляции, мы просто создаем экземпляр этого класса и вызываем любые члены экземпляра. Это раннее связывание.
//Early Binding
**Employee** employeeObject = new **Employee**();
employeeObject.CalculateSalary();
С другой стороны, если у вас нет знаний о классе во время компиляции, то единственным способом является поздняя привязка с использованием отражения. Я столкнулся с отличным видео, объясняющим эти понятия - здесь ссылка.
Ответ 4
В очень простых терминах раннее связывание происходит во время компиляции, и у компилятора есть знания о типе и всех его членах, а поздняя привязка происходит во время выполнения, компилятор ничего не знает о типе и его членах. Я столкнулся с отличным видео на YouTube, которое объясняет эти понятия.
http://www.youtube.com/watch?v=s0eIgl5iqqQ&list=PLAC325451207E3105&index=55&feature=plpp_video
http://www.youtube.com/playlist?list=PLAC325451207E3105
Ответ 5
Это очень старый пост, но он хотел добавить к нему дополнительную информацию. Позднее привязка используется, когда вы не хотите создавать экземпляр объекта во время компиляции. В C#
вы используете Activator
для вызова объекта привязки во время выполнения.
Ответ 6
Ранняя привязка
Само имя описывает, что компилятор знает, какой именно объект он представляет, какие все методы и свойства он содержит. Как только вы объявите объект,.NET Intellisense будет заполнять свои методы и свойства нажатием кнопки точки.
Общие примеры:
ComboBox cboItems;
ListBox lstItems;
В приведенных выше примерах, если мы наберем cboItem и поместим точку, за которой последует, она автоматически заполнит все методы, события и свойства поля со списком, потому что компилятор уже знает это combobox.
Поздняя привязка
Само название описывает, что компилятор не знает, что это за объект, какие все методы и свойства он содержит. Вы должны объявить его как объект, позже вам нужно получить тип объекта, методы, которые хранятся в нем. Все будет известно во время выполнения.
Общие примеры:
Объектные объекты;
objItems = CreateObject ( "DLL или имя сборки" );
Здесь во время компиляции тип объектов не определяется. Мы создаем объект dll и присваиваем его объектам, поэтому все определяется во время выполнения.
Ранняя привязка против поздней привязки
Теперь входим в картину...
Приложение будет работать быстрее в раннем привязке, так как здесь нет бокса или распаковки.
Легче писать код в раннем связывании, так как intellisense будет автоматически заполняться
Минимальные ошибки в раннем связывании, так как синтаксис проверяется во время самого компиляции.
Поздняя привязка будет поддерживаться во всех версиях, так как все определяется во время выполнения.
Минимальное воздействие кода в будущих улучшениях, если используется Late Binding.
Производительность будет кодом раннего связывания.
Оба имеют достоинства и недостатки, это решение разработчика выбрать подходящую привязку на основе сценария.
Ответ 7
Эта статья является руководством по созданию компонента .net, используя его в проекте Vb6 во время выполнения с использованием позднего связывания, прикрепляя его к событиям и получая обратный вызов.
http://www.codeproject.com/KB/cs/csapivb6callback2.aspx