2010-11-17 16 views
6

Làm cách nào để xác định xem phương thức có cần được gọi bằng "Gọi" hoặc "Gọi điện" không?.NET CIL Call hoặc CallVirt?

+4

Điều này phải làm gì với C#? – SLaks

Trả lời

4

Bạn có thể làm theo các quy tắc đơn giản từng người một để xác định mà bạn nên sử dụng:

  • Là phương pháp static? Sau đó sử dụng call.
  • Loại bạn đang gọi trên một loại giá trị? Sau đó sử dụng call. (này không áp dụng nếu giá trị được đóng hộp - sau đó bạn đang thực sự gọi trên object hoặc một số giao diện, và đó là những loại tài liệu tham khảo.)
  • là phương pháp bạn đang gọi tuyên bố virtual hoặc abstract? Sau đó sử dụng callvirt.
  • Bạn có gọi phương thức thông qua tham chiếu giao diện không? Sau đó sử dụng callvirt.
  • Phương pháp bạn đang gọi được khai báo là override, nhưng cả phương pháp và loại khai báo đều không khai báo sealed? Sau đó sử dụng callvirt.

Trong mọi trường hợp khác, không có công văn ảo là cần thiết, do đó bạn có thể sử dụng call - nhưng bạn nên sử dụng callvirt. Đây là lý do:

Sử dụng callvirt trên phương pháp không phải ảo tương đương với call trừ khi đối số đầu tiên là rỗng. Trong trường hợp đó, callvirt sẽ ném một số NullReferenceException ngay lập tức, trong khi call thì không. Điều này có ý nghĩa, bởi vì callvirt được thiết kế để được sử dụng trong trường hợp gửi phương thức ảo, và bạn không thể thực hiện phương thức ảo nếu bạn không có đối tượng để thực hiện tra cứu vtable.

Lưu ý rằng callvirt sẽ vẫn ném ngoại lệ nếu đối số đầu tiên là null ngay cả khi tra cứu vtable là không cần thiết!

Xét thông tin này, sử dụng callvirt cho tất cả các phương pháp invocations không tĩnh trên các loại tài liệu tham khảo (tùy theo từng biên dịch C# không) có thể là một lợi thế vì nó sẽ gây ra một NullReferenceException ngay tại địa điểm cuộc gọi thay vì đôi khi sau khi this được sử dụng (một cách rõ ràng hoặc ngầm) bên trong phương thức.

+0

Nhưng .NET sử dụng "gọi" khi gọi một cái gì đó như Point.X. Từ những gì tôi đang đọc phương pháp loại giá trị rõ ràng sử dụng "gọi". – Will

+2

Có, bởi vì những phương pháp đó không phải là ảo, vì vậy tôi mong đợi đầu ra sẽ sử dụng "cuộc gọi". Đọc lại câu trả lời của tôi. (Ngoài ra, cấu trúc * không thể * có các thành viên ảo vì chúng không thể được kế thừa.) – cdhowie

+0

Điều đó có ý nghĩa, cảm ơn. Chỉ cần kỳ quặc rằng sự phản chiếu cho thấy "IsVirtual" là đúng đối với các phương thức struct. – Will

6

Theo mặc định, trình biên dịch C# luôn sử dụng lời gọi cho mọi thứ ngoại trừ các cuộc gọi kiểu tĩnh hoặc giá trị. Điều này gây ra việc kiểm tra null ngầm định đối số 'this' (arg0). Bạn không bắt buộc phải tuân theo quy ước này, nhưng mọi phương thức ảo trên một kiểu tham chiếu chắc chắn sẽ yêu cầu callvirt.

+1

Ngoại trừ các phương pháp ảo trên các lớp được niêm phong. –

0

Nếu bạn sử dụng cuộc gọi trong dynamicmethod trên một phương pháp ảo thời gian chạy ném một ngoại lệ bảo mật.

Các vấn đề liên quan