Рання та пізня палітурка


83

Я намагаюся розібратися, коли раннє / пізнє зв'язування відбувається в C #.

Невіртуальні методи завжди ранні. Віртуальні методи завжди мають пізні обмеження: компілятор вставляє додатковий код для розв’язання фактичного методу, до якого прив’язується під час виконання, та перевіряє безпеку типу. Отже, підтип поліморфізму використовує пізнє зв'язування.

Методи виклику з використанням рефлексії є прикладом пізнього зв'язування. Для досягнення цього ми пишемо код, на відміну від компілятора. (Наприклад, виклик COM-компонентів.)

VB.NET підтримує неявне пізнє прив'язування, коли Option Strict вимкнено. Об’єкт пізно прив’язаний, коли йому присвоюється змінна, оголошена типом Object. Компілятор VB вставляє код для прив'язки до потрібного методу під час виконання та для виявлення недійсних викликів. C # не підтримує цю функцію.

Я йду в правильному напрямку?

А як щодо виклику делегатів та виклику методу через посилання на інтерфейс? Це рання чи пізня прив'язка?

Відповіді:


102

Все на початку обмежено C #, якщо ви не пройдете інтерфейс Reflection.

Рання прив'язка просто означає, що цільовий метод знайдений під час компіляції, і створюється код, який викликатиме це. Незалежно від того, віртуальний він чи ні (це означає, що є додатковий крок, щоб знайти його під час дзвінка, не має значення). Якщо метод не існує, компілятор не зможе скомпілювати код.

Пізній зв’язок означає, що цільовий метод шукається під час виконання. Часто для його пошуку використовують текстову назву методу. Якщо методу немає, бах. Програма виведе з ладу або перейде в якусь схему обробки винятків під час роботи.

Більшість мов сценаріїв використовують пізнє прив'язування, а компільовані мови використовують раннє прив'язку.

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

Зв'язування зазвичай впливає на продуктивність. Оскільки пізнє прив'язування вимагає пошуку під час виконання, це, як правило, означає, що виклики методів є повільнішими, ніж виклики методів, що прив'язані до початку.


Для нормальної функції компілятор може обробити числове розташування його в пам'яті. Тоді він, коли функція викликається, може генерувати вказівку викликати функцію за цією адресою.

Для об'єкта, який має будь-які віртуальні методи, компілятор генерує v-таблицю. По суті, це масив, що містить адреси віртуальних методів. Кожен об'єкт, який має віртуальний метод, буде містити прихований член, сформований компілятором, який є адресою v-таблиці. Коли викликана віртуальна функція, компілятор визначить, яке положення займає відповідний метод у v-таблиці. Потім він генерує код для пошуку в об’єктах v-table та викликає віртуальний метод у цій позиції.

Отже, існує пошук, який відбувається для віртуальної функції. Це сильно оптимізовано, тому це буде відбуватися дуже швидко під час виконання.

Рано зв'язаний

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

Пізньо-обов’язковий

  • Пошук триватиме довше, оскільки це не простий обчислювальний зсув, як правило, потрібно зробити порівняння тексту.
  • Цільова функція може не існувати.
  • Цільова функція може не приймати аргументи, передані їй, і може мати повернене значення неправильного типу.
  • У деяких реалізаціях цільовий метод може фактично змінюватися під час виконання. Отже, пошук може виконувати іншу функцію. Я думаю, що це відбувається в мові Ruby, ви можете визначити новий метод на об'єкті під час роботи програми. Пізнє прив'язування дозволяє викликам функцій почати виклик нового перевизначення для методу замість виклику існуючого базового методу.

Я думаю, ви хотіли сказати: "Сама мова VB не запізнюється ..."
Майкл Медоуз,

Насправді я не використовую VB ... тому я не знаю багато про це. Я мав на увазі C #, але схоже, я просто повторював себе. Я міг би уявити, що ти маєш рацію, тож я це виправлю!
Скотт Ленгем

21
Динамічне введення тексту - це не те саме, що пізнє прив’язування. Різниця незначна, але важлива. Пізнє прив'язування все ще прив'язується до типу, воно просто робить це під час виконання. Динамічне введення тексту не пов’язує; натомість він вирішує інформацію про членів під час виконання, незалежно від типу.
Michael Meadows

1
Msgstr " Для об'єкта, який має будь-які віртуальні методи, компілятор генерує v-таблицю. " Це трохи неправильно - "клас", а не "об'єкт".
turdus-merula

1
@IvanRuski Я не думаю. Під час компіляції відомі всі типи аргументів, які приймає делегат. Отже, під час компіляції (що є "ранньою"), а не під час виконання (яка "пізня"), компілятор може гарантувати, що виклик буде працювати.
Скотт Ленгем,

18

C # 3 використовує раннє зв'язування.

C # 4 додає пізнє прив'язку за dynamicключовим словом. Детальніше дивіться в блозі Кріса Берроу на цю тему.

Що стосується віртуальних та невіртуальних методів, це інша проблема. Якщо я зателефоную string.ToString(), код C # прив'язаний до віртуального object.ToString()методу. Код абонента не змінюється залежно від типу об'єкта. Швидше, віртуальні методи викликаються через таблицю покажчиків на функції. Екземпляр об'єкта посилається на таблицю об'єкта, що вказує на його ToString()метод. Екземпляр рядка має віртуальну таблицю методів, що вказує на його ToString()метод. Так, це поліморфізм. але це не пізнє зв'язування.


1
Я не повністю згоден з цим поясненням. У C # позначення методу або поля екземпляра як віртуального засобу похідний тип може замінити реалізацію базового типу в ланцюжку успадкування. За допомогою віртуальних методів CLR знає, який метод викликати під час виконання на основі екземпляра об’єкта часу виконання. Напевно, єдине, що я з вами погоджуюсь, це реалізація поліморфізму. Тоді ви викликаєте плутанину, кажучи, що це не пізнє зобов’язування. Це пізнє прив’язування, оскільки CLR може викликати правильну реалізацію типу часу виконання лише тоді, коли він знає тип часу виконання екземпляра об’єкта.
Юлій Депулла

6

У більшості випадків завчасне прив’язування - це те, що ми робимо щодня. Наприклад, якщо у нас є Employeeклас, доступний під час компіляції, ми просто створюємо екземпляр цього класу і викликаємо будь-які члени екземпляра. Це дострокове зобов’язування.

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

З іншого боку, якщо ви не маєте знань про клас під час компіляції, тоді єдиний спосіб - це запізніле прив’язування за допомогою рефлексії. Я натрапив на чудове відео, що пояснює ці концепції - ось посилання .


3

Це дуже стара публікація, але я хотів додати до неї більше інформації. Пізнє прив'язування використовується, коли ви не хочете створювати екземпляр об'єкта під час компіляції. У C#використанні Activatorдля виклику прив'язки об'єкта під час виконання.


3

Рання прив'язка

Сама назва описує, що компілятор знає про те, що це за об'єкт, які всі методи та властивості він містить. Як тільки ви оголосите об'єкт, .NET Intellisense заповнить його методи та властивості, натиснувши кнопку крапки.

Поширені приклади:

ComboBox cboItems;

ListBox lstItems; У наведених вище прикладах, якщо ми введемо cboItem і розмістимо крапку, за якою слідує крапка, вона автоматично заповнить усі методи, події та властивості комбінованого поля, оскільки компілятор вже знає, що це комбобокс.

Пізня прив'язка

Сама назва описує, що компілятор не знає, що це за об'єкт, які всі методи та властивості він містить. Вам потрібно оголосити його як об'єкт, пізніше потрібно отримати тип об'єкта, методи, які в ньому зберігаються. Все буде відомо під час виконання.

Поширені приклади:

Об'єкт objItems;

objItems = CreateObject ("DLL або ім'я збірки"); Тут під час компіляції тип objItems не визначається. Ми створюємо об’єкт DLL і призначаємо його об’єктам objItems, тому все визначається під час виконання.

Рання прив'язка проти пізньої прив'язки

Зараз входить у картину ...

Додаток буде працювати швидше в режимі раннього прив'язки, оскільки тут не проводиться бокс чи розпакування.

Простіше написати код у Достроковому прив'язуванні, оскільки intellisense буде автоматично заповнено

Мінімальні помилки при ранньому прив'язуванні, оскільки синтаксис перевіряється під час самого компіляції.

Пізнє прив'язування підтримуватиме всі версії, оскільки все вирішується під час виконання.

Мінімальний вплив коду на майбутні вдосконалення, якщо використовується пізнє прив’язування.

Продуктивність буде кодом на початку прив'язки. І те, і інше має переваги та недоліки, тому розробник вирішує вибрати відповідну прив'язку на основі сценарію.


2

Якщо говорити дуже просто, раннє прив’язування відбувається під час компіляції, і компілятор має знання про тип та всіх його членів, а пізнє прив’язування відбувається під час виконання, компілятор нічого не знає про тип та його членів. Я натрапив на чудове відео на YouTube, яке пояснює ці поняття.

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

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


1

Ця стаття - посібник зі створення компонента .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, і це є серйозною проблемою, якщо ви не можете їх правильно розгорнути. Просто погуґлюйте про проблеми розповсюдження shdocvw та mshtml.dll, і ви побачите, про що я говорю. Вам слід розгорнути 8 MB MB.mshtml.dll, оскільки ця DLL не є частиною .NET-середовища. У цьому випадку нам потрібно використовувати техніку пізнього зв’язування. Написання власних обгортків для вищезгаданих бібліотек DLL. І звичайно, ми зробимо це, оскільки це корисніше, ніж використання цих бібліотек DLL. Наприклад, нам не потрібно буде перевіряти, чи завершена операція завантаження документа, оскільки IEHelper зробить це за нас.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.