Ràng buộc sớm và muộn


83

Tôi đang cố gắng xoay sở khi liên kết sớm / muộn xảy ra trong C #.

Các phương pháp không ảo luôn bị ràng buộc sớm. Các phương thức ảo luôn bị ràng buộc muộn: trình biên dịch chèn thêm mã để phân giải phương thức thực cần liên kết vào lúc thực thi và kiểm tra độ an toàn của kiểu. Vì vậy, đa hình kiểu con sử dụng liên kết muộn.

Phương thức gọi sử dụng phản xạ là một ví dụ của ràng buộc muộn. Chúng tôi viết mã để đạt được điều này trái ngược với trình biên dịch. (Ví dụ: gọi các thành phần COM.)

VB.NET hỗ trợ ràng buộc trễ ngầm khi tắt tùy chọn nghiêm ngặt. Một đối tượng bị ràng buộc muộn khi nó được gán cho một biến được khai báo là kiểu Đối tượng. Trình biên dịch VB chèn mã để liên kết với phương thức phù hợp tại thời điểm thực thi và bắt các cuộc gọi không hợp lệ. C # không hỗ trợ tính năng này.

Tôi có đang đi đúng hướng không?

Điều gì về việc gọi các đại biểu và gọi một phương thức thông qua một tham chiếu giao diện? Đó là sự ràng buộc sớm hay muộn?

Câu trả lời:


102

Mọi thứ đều bị ràng buộc sớm trong C # trừ khi bạn đi qua giao diện Reflection.

Giới hạn sớm chỉ có nghĩa là phương thức đích được tìm thấy tại thời điểm biên dịch và mã được tạo sẽ gọi điều này. Cho dù nó ảo hay không (có nghĩa là có thêm một bước để tìm nó vào thời gian cuộc gọi là không liên quan). Nếu phương thức không tồn tại, trình biên dịch sẽ không biên dịch được mã.

Giới hạn muộn có nghĩa là phương thức đích được tra cứu vào thời gian chạy. Thường thì tên văn bản của phương thức được sử dụng để tra cứu nó. Nếu phương pháp không có ở đó, hãy nổ. Chương trình sẽ gặp sự cố hoặc đi vào một số sơ đồ xử lý ngoại lệ tại thời điểm chạy.

Hầu hết các ngôn ngữ tập lệnh sử dụng liên kết muộn và các ngôn ngữ đã biên dịch sử dụng liên kết sớm.

C # (trước phiên bản 4) không ràng buộc muộn; Tuy nhiên, họ có thể sử dụng API phản chiếu để làm điều đó. API đó biên dịch thành mã tìm kiếm tên hàm bằng cách đào qua các hội đồng tại thời điểm chạy. VB có thể ràng buộc muộn nếu tùy chọn nghiêm ngặt bị tắt.

Ràng buộc thường có ảnh hưởng đến hiệu suất. Bởi vì ràng buộc muộn yêu cầu tra cứu trong thời gian chạy, điều đó thường có nghĩa là các lệnh gọi phương thức chậm hơn các lệnh gọi phương thức ràng buộc sớm.


Đối với một chức năng bình thường, trình biên dịch có thể tìm ra vị trí số của nó trong bộ nhớ. Sau đó, khi hàm được gọi, nó có thể tạo ra lệnh để gọi hàm tại địa chỉ này.

Đối với một đối tượng có bất kỳ phương thức ảo nào, trình biên dịch sẽ tạo ra một bảng v. Đây thực chất là một mảng chứa địa chỉ của các phương thức ảo. Mọi đối tượng có một phương thức ảo sẽ chứa một phần tử ẩn được tạo bởi trình biên dịch đó là địa chỉ của v-table. Khi một hàm ảo được gọi, trình biên dịch sẽ tìm ra vị trí của phương thức thích hợp trong v-table. Sau đó, nó sẽ tạo ra mã để tìm kiếm trong các đối tượng v-table và gọi phương thức ảo tại vị trí này.

Vì vậy, có một tra cứu xảy ra cho hàm ảo. Điều này được tối ưu hóa rất nhiều nên nó sẽ diễn ra rất nhanh trong thời gian chạy.

Ràng buộc sớm

  • Trình biên dịch có thể tìm ra vị trí của hàm được gọi tại thời điểm biên dịch.
  • Trình biên dịch có thể đảm bảo sớm (trước khi bất kỳ mã chương trình nào chạy) rằng hàm sẽ tồn tại và có thể gọi được trong thời gian chạy.
  • Trình biên dịch đảm bảo rằng hàm nhận đúng số lượng đối số và chúng thuộc loại chính xác. Nó cũng kiểm tra xem giá trị trả về có đúng loại không.

Ràng buộc muộn

  • Việc tra cứu sẽ mất nhiều thời gian hơn vì nó không phải là một phép tính bù đơn giản, thường phải thực hiện so sánh văn bản.
  • Chức năng đích có thể không tồn tại.
  • Hàm đích có thể không chấp nhận các đối số được truyền cho nó và có thể có giá trị trả về không đúng kiểu.
  • Với một số triển khai, phương thức đích thực sự có thể thay đổi trong thời gian chạy. Vì vậy, việc tra cứu có thể thực thi một chức năng khác. Tôi nghĩ rằng điều này xảy ra trong ngôn ngữ Ruby, bạn có thể định nghĩa một phương thức mới trên một đối tượng trong khi chương trình đang chạy. Liên kết muộn cho phép các lệnh gọi hàm bắt đầu gọi ghi đè mới cho một phương thức thay vì gọi phương thức cơ sở hiện có.

Tôi nghĩ bạn có ý nói "Bản thân ngôn ngữ VB không bị ràng buộc muộn ..."
Michael Meadows 27/01/09

Thực ra, tôi không sử dụng VB ... nên tôi không biết nhiều về điều đó. Ý tôi là C #, nhưng có vẻ như tôi chỉ đang lặp lại chính mình. Tôi sẽ tưởng tượng rằng bạn đúng, vì vậy tôi sẽ sửa nó!
Scott Langham

21
Nhập động không giống như liên kết muộn. Sự khác biệt là nhỏ, nhưng nó quan trọng. Liên kết muộn vẫn liên kết với một kiểu, nó chỉ thực hiện điều đó trong thời gian chạy. Nhập động không ràng buộc; thay vào đó, nó giải quyết thông tin thành viên trong thời gian chạy không phân biệt loại.
Michael Meadows

1
" Đối với một đối tượng có bất kỳ phương thức ảo nào, trình biên dịch sẽ tạo ra một bảng v. ". Điều này hơi không chính xác - "lớp", không phải "đối tượng".
turdus-merula

1
@IvanRuski Tôi không nghĩ vậy. Tại thời điểm biên dịch, tất cả các kiểu đối số mà một đại biểu chấp nhận đều được biết đến. Vì vậy, tại thời điểm biên dịch (là 'sớm') thay vì thời gian chạy (là 'muộn'), trình biên dịch có thể đảm bảo rằng lệnh gọi sẽ hoạt động.
Scott Langham

18

C # 3 sử dụng ràng buộc sớm.

C # 4 thêm ràng buộc muộn với dynamictừ khóa. Xem mục blog của Chris Burrow về chủ đề này để biết thêm chi tiết.

Đối với các phương pháp ảo và không ảo, đây là một vấn đề khác. Nếu tôi gọi string.ToString(), mã C # được liên kết với object.ToString()phương thức ảo . Mã của người gọi không thay đổi dựa trên loại đối tượng. Đúng hơn, các phương thức ảo được gọi thông qua một bảng con trỏ hàm. Một thể hiện của đối tượng đề cập đến bảng của đối tượng chỉ vào ToString()phương thức của nó . Một trường hợp của chuỗi có bảng phương thức ảo của nó trỏ vào ToString()phương thức của nó . Vâng, đây là tính đa hình. nhưng nó không phải là ràng buộc muộn.


1
Tôi không hoàn toàn đồng ý với lời giải thích này. Trong C #, việc đánh dấu một phương thức hoặc trường thể hiện là kiểu dẫn xuất phương tiện ảo có thể ghi đè việc triển khai kiểu cơ sở trong chuỗi kế thừa. Với các phương thức ảo, CLR biết phương thức nào cần gọi tại thời điểm chạy dựa trên cá thể đối tượng thời gian chạy. Có lẽ, phần duy nhất tôi đồng ý với bạn là, nó là một triển khai của đa hình. Sau đó, bạn gây ra sự nhầm lẫn bằng cách nói rằng nó không phải là ràng buộc muộn. Nó là ràng buộc muộn vì CLR chỉ có thể gọi thực thi kiểu thời gian chạy chính xác khi nó biết kiểu thời gian chạy của cá thể đối tượng.
Julius Depulla

6

Trong hầu hết các trường hợp, ràng buộc sớm là việc chúng ta làm hàng ngày. Ví dụ: nếu chúng ta có Employeesẵn một lớp tại thời điểm biên dịch, chúng ta chỉ cần tạo thể hiện của lớp đó và gọi bất kỳ thành viên nào của thể hiện. Đây là ràng buộc sớm.

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

Mặt khác, nếu bạn không có kiến ​​thức về lớp tại thời điểm biên dịch, thì cách duy nhất là kết thúc trễ bằng cách sử dụng phản chiếu. Tôi đã xem qua một video tuyệt vời giải thích những khái niệm này - đây là liên kết .


3

Đó là một bài viết rất cũ nhưng muốn thêm thông tin vào nó. Liên kết muộn được sử dụng khi bạn không muốn khởi tạo đối tượng tại thời điểm biên dịch. Trong C#bạn sử dụng Activatorđể gọi đối tượng bind trong thời gian chạy.


3

Ràng buộc sớm

Bản thân cái tên mô tả trình biên dịch đó biết nó là loại đối tượng gì, tất cả các phương thức và thuộc tính nó chứa là gì. Ngay sau khi bạn khai báo đối tượng, .NET Intellisense sẽ điền các phương thức và thuộc tính của nó khi nhấp vào nút dấu chấm.

Các ví dụ phổ biến:

ComboBox cboItems;

ListBox lstItems; Trong các ví dụ trên, nếu chúng ta nhập cboItem và đặt một dấu chấm theo sau, nó sẽ tự động điền tất cả các phương thức, sự kiện và thuộc tính của một hộp tổ hợp, vì trình biên dịch đã biết đó là một hộp tổ hợp.

Ràng buộc muộn

Bản thân cái tên mô tả trình biên dịch đó không biết nó là loại đối tượng gì, tất cả các phương thức và thuộc tính nó chứa là gì. Bạn phải khai báo nó như một đối tượng, sau này bạn cần lấy kiểu của đối tượng, các phương thức được lưu trữ trong nó. Mọi thứ sẽ được biết vào thời gian chạy.

Các ví dụ phổ biến:

Đối tượng objItems;

objItems = CreateObject ("Tên DLL hoặc Assembly"); Ở đây trong thời gian biên dịch, loại objItems không được xác định. Chúng tôi đang tạo một đối tượng của một dll và gán nó cho objItems, vì vậy mọi thứ được xác định tại thời điểm chạy.

Ràng buộc sớm so với Ràng buộc muộn

Bây giờ đi vào bức tranhâ € ¦

Ứng dụng sẽ chạy nhanh hơn trong Liên kết sớm, vì không có quyền anh hoặc mở hộp nào được thực hiện ở đây.

Dễ dàng hơn để viết mã trong Liên kết sớm, vì intellisense sẽ được tự động điền

Lỗi tối thiểu trong liên kết sớm, vì cú pháp được kiểm tra trong chính thời gian biên dịch.

Ràng buộc muộn sẽ hỗ trợ trong tất cả các loại phiên bản, vì mọi thứ đều được quyết định tại thời điểm chạy.

Tác động tối thiểu của mã trong các cải tiến trong tương lai, nếu sử dụng Trói buộc muộn.

Hiệu suất sẽ là mã trong ràng buộc sớm. Cả hai đều có giá trị và điểm yếu, đó là quyết định của nhà phát triển để chọn ràng buộc phù hợp dựa trên kịch bản.


2

Nói một cách đơn giản, liên kết sớm xảy ra tại thời điểm biên dịch và trình biên dịch có kiến ​​thức về kiểu và tất cả các thành viên của nó, và ràng buộc muộn xảy ra tại thời điểm chạy, trình biên dịch không biết gì về kiểu và nó là thành viên. Tôi đã xem một video xuất sắc trên youtube giải thích những khái niệm này.

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

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


1

Bài viết này là hướng dẫn xây dựng một thành phần .net, sử dụng nó trong một dự án Vb6 trong thời gian chạy bằng cách sử dụng liên kết muộn, đính kèm các sự kiện của nó và nhận một cuộc gọi lại.

http://www.codeproject.com/KB/cs/csapivb6callback2.aspx

Bài viết này là hướng dẫn xây dựng một thành phần .NET và sử dụng nó trong một dự án VB6. Có rất nhiều mẫu về vấn đề này, vậy tại sao tôi lại viết một bài mới? Theo ý kiến ​​khiêm tốn của tôi, trong các bài báo khác, phần còn thiếu là đính kèm sự kiện của nó trong thời gian chạy. Vì vậy, trong bài viết này, chúng ta sẽ xây dựng một thành phần .NET, đánh dấu nó là một thành phần có thể nhìn thấy COM, sử dụng nó trong thời gian chạy trong VB6 và gắn vào các sự kiện của nó.

https://www.codeproject.com/Articles/37127/Internet-Explorer-Late-Binding-Automation

Hầu hết các nhà phát triển thường cần tự động hóa Internet Explorer, về cơ bản có nghĩa là mở trình duyệt, điền vào một số biểu mẫu và đăng dữ liệu theo chương trình.

Phương pháp phổ biến nhất là sử dụng shdocvw.dll (điều khiển Trình duyệt web của Microsoft) và Mshtml.dll (Thành phần phân tích cú pháp và kết xuất HTML) hoặc Microsoft.Mshtml.dll thực sự là trình bao bọc .NET cho Mshtml.dll. Bạn có thể lấy thêm thông tin về Internet Explorer - Giới thiệu về Trình duyệt tại đây.

Nếu bạn chọn phương pháp trên và các tệp DLL, hãy xem một số vấn đề bạn có thể phải giải quyết:

Bạn phải phân phối các DLL này vì dự án của bạn sẽ phụ thuộc vào các DLL này và đây là một vấn đề nghiêm trọng nếu bạn không thể triển khai chúng một cách chính xác. Chỉ cần thực hiện một số Googling về vấn đề phân phối shdocvw và mshtml.dll, và bạn sẽ thấy những gì tôi đang nói. Bạn phải triển khai Microsoft.mshtml.dll 8 MB vì ​​DLL này không phải là một phần của .NET framework. Trong trường hợp này, những gì chúng ta cần làm là sử dụng kỹ thuật ràng buộc muộn. Viết các trình bao bọc của riêng chúng tôi cho các tệp DLL được đề cập ở trên. Và tất nhiên, chúng tôi sẽ làm điều này vì nó hữu ích hơn việc sử dụng các DLL này. Ví dụ: chúng tôi sẽ không cần kiểm tra xem hoạt động tải xuống tài liệu đã hoàn tất chưa vì IEHelper sẽ thực hiện việc này cho chúng tôi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.