Метод розширення та динамічний об'єкт


96

Я збираюся резюмувати свою проблему в наступному фрагменті коду.

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

Наведений вище код працює нормально.

Зараз я спробував наступне

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

але я отримую RuntimeBinderException. Чому це так?


Це здається , що дублікат цього питання просив всього 4 дні тому stackoverflow.com/questions/5270782 / ...
jbtule

@jbtule Різниця в тому, що thisтут тут динамічно, але якщо ви приземлитесь тут, вам, мабуть, слід також поглянути на це питання
nik.shornikov

Відповіді:


131

Щоб розширити відповідь Stecya ... методи розширення не підтримуються динамічним набором у формі методів розширення , тобто викликаються так, ніби це методи екземпляра. Однак це буде працювати:

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

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


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

19
@geek: Особисто моє емпіричне правило полягає лише у використанні dynamicтам, де вам справді потрібно ... в основному, якщо ви в іншому випадку отримували б доступ до учасників з роздумами, це великий знак. З іншого боку, я твердий статичний друкар - інші можуть пропонувати менш песимістичну політику :)
Джон Скіт,

2
Це може бути більш читабельним для повернення до відомого типу, це працює: Console.WriteLine (((List <int>) dList) .First ()); Або Console.WriteLine ((dList as List <int>). First ()) ;.
AVee

138

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

Це означає, що для того, щоб отримати виклик методу динамічного розширення правильно вирішеним, якимось чином DLR повинен знати під час виконання, які всі вкладеності та usingдирективи простору імен були у вашому вихідному коді . У нас немає зручного механізму для кодування всієї цієї інформації на сайті виклику. Ми розглядали можливість винайти такий механізм, але вирішили, що це занадто висока вартість і спричиняє занадто великий ризик, щоб коштувати того.


Щиро дякую за пояснення.
Сантош Сінгх

3
Чи є така особливість на початку? Це, безумовно, була б надзвичайною зміною; дзвінки, які зараз викидають RunTimeBinderExceptions, раптово почнуть працювати при перекомпіляції джерела. Крім того, чи існують якісь ризики безпеки, пов’язані з реалізацією такої функції?
Ані

5
@ani: Ми плануємо впровадити цю функцію? Ні. Чи є загрози безпеці? Я не знаю жодного; про який ризик безпеки ви мали на увазі? Почніть з того, що скажете, хто зловмисник і яку загрозу вони створюють для користувача.
Ерік Ліпперт,

@EricLippert, я зрозумів, що всі dynamicоб'єкти рівні C #:, DynamicObjectтому немає можливості їх диференціювати, і це одна з причин, чому неможливо додати методи розширення dynamic, вірно?
Том Сардуй,

@EricLippert подумайте про те, щоб ще трохи розширити цю відповідь і додати речення в рядку "Коли будь-який із параметрів є динамічним, тоді всі дозволи відкладаються до часу виконання". Хоча це очевидно для вас це важливо , трохи важко знайти де - небудь ще на SO (див stackoverflow.com/questions/48324768 , наприклад)
Олексій Левенко

18

Тому що First()це не метод List. Це визначено у Розширенні Linq доIEnumerable<>

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