Phương thức mở rộng và đối tượng động


96

Tôi sẽ tóm tắt vấn đề của mình thành đoạn mã sau.

List<int> list = new List<int>() { 5, 56, 2, 4, 63, 2 };
Console.WriteLine(list.First());

Đoạn mã trên đang hoạt động tốt.

Bây giờ tôi đã thử những điều sau

dynamic dList = list;
 Console.WriteLine(dList.First());

nhưng tôi đang nhận được RuntimeBinderException. Tại sao nó lại như vậy?


Đây có vẻ như là một bản sao của câu hỏi này được hỏi chỉ 4 ngày trước stackoverflow.com/questions/5270782/…
jbtule

@jbtule Sự khác biệt là những thislà năng động ở đây, nhưng nếu bạn hạ cánh ở đây, có lẽ bạn nên nhìn vào câu hỏi đó quá
nik.shornikov

Câu trả lời:


131

Để mở rộng câu trả lời của Stecya ... các phương thức mở rộng không được hỗ trợ bằng cách nhập động dưới dạng các phương thức mở rộng , tức là được gọi như thể chúng là các phương thức cá thể. Tuy nhiên, điều này sẽ hoạt động:

dynamic dList = list;
Console.WriteLine(Enumerable.First(dList));

Tất nhiên, điều đó có thể hữu ích hoặc không. Nếu bạn có thể cung cấp thêm thông tin về lý do và cách bạn đang cố gắng sử dụng nhập động, chúng tôi có thể trợ giúp thêm.


Tôi đã chơi với đối tượng năng động và có exception.Do này bạn đã viết bất kỳ bài viết về chủ đề này, nơi để sử dụng hoặc không sử dụng động vật
Santosh singh

19
@geek: Cá nhân tôi quy tắc ngón tay cái là chỉ sử dụng dynamicở những nơi bạn thực sự cần ... về cơ bản nếu bạn muốn truy cập các thành viên có phản ánh, đó là một dấu hiệu lớn. Mặt khác, tôi là một tĩnh typer chết cứng - những người khác có thể gợi ý chính sách ít bi quan :)
Jon Skeet

2
Nó có thể dễ đọc hơn khi truyền về kiểu know, điều này hoạt động: Console.WriteLine (((List <int>) dList) .First ()); Hoặc Console.WriteLine ((dList as List <int>) .First ()) ;.
AVee

138

Để mở rộng câu trả lời của Jon, lý do điều này không hoạt động là vì trong các phương thức mở rộng mã không động, thông thường hoạt động bằng cách thực hiện tìm kiếm đầy đủ tất cả các lớp mà trình biên dịch biết cho một lớp tĩnh có phương thức mở rộng phù hợp. Việc tìm kiếm diễn ra theo thứ tự dựa trên lồng không gian tên và các usingchỉ thị có sẵn trong mỗi không gian tên.

Điều đó có nghĩa là để giải quyết lệnh gọi phương thức mở rộng động một cách chính xác, bằng cách nào đó DLR phải biết trong thời gian chạy tất cả các usingchỉ thị và lồng không gian tên trong mã nguồn của bạn . Chúng tôi không có một cơ chế hữu ích để mã hóa tất cả thông tin đó vào trang web cuộc gọi. Chúng tôi đã cân nhắc việc phát minh ra một cơ chế như vậy, nhưng quyết định rằng chi phí quá cao và tạo ra quá nhiều rủi ro về lịch trình không đáng có.


Cảm ơn bạn rất nhiều cho lời giải thích.
santosh singh

3
Đó có phải là một tính năng đang diễn ra? Đó chắc chắn sẽ là một sự thay đổi đột phá; các lệnh gọi hiện đang ném RunTimeBinderExceptions sẽ đột nhiên bắt đầu hoạt động khi biên dịch lại nguồn. Ngoài ra, liệu có bất kỳ rủi ro bảo mật nào liên quan đến việc triển khai một tính năng như vậy không?
Ani

5
@ani: Chúng tôi có kế hoạch triển khai tính năng đó không? Không. Có bất kỳ rủi ro bảo mật nào không? Tôi không biết về bất kỳ; bạn đã nghĩ đến loại rủi ro bảo mật nào? Bắt đầu bằng cách nói ai là kẻ tấn công và họ đang gây ra mối đe dọa nào đối với người dùng.
Eric Lippert

@EricLippert, tôi đã hiểu rằng tất cả dynamiccác đối tượng đều bằng C # : DynamicObject, vì vậy không có cách nào để phân biệt chúng và là một trong những lý do tại sao không thể thêm các phương thức mở rộng vào dynamic, đúng không?
Tom Sarduy

@EricLippert xem xét để mở rộng câu trả lời này hơn một chút và thêm câu dọc theo dòng "Khi bất kỳ tham số nào là động, thì tất cả các độ phân giải được hoãn lại cho đến thời gian chạy". Trong khi nó rõ ràng cho bạn chút quan trọng này là khó có thể tìm thấy bất cứ nơi nào khác trên SO (xem stackoverflow.com/questions/48324768 ví dụ)
Alexei Levenkov

18

Bởi vì First()không phải là một phương pháp của List. Nó được định nghĩa trong Linq Extension đểIEnumerable<>

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.