Решение
Некоторое исследование и лучшее прочтение , ранее упомянутое Хансом Пассантом в статье , приводит к следующему выводу:
- VB.NET 2010 поддерживает DLR;
- Вы можете реализовать
IDynamicMetaObjectProvider
, если вы хотите явно поддерживать динамику, компилятор VB.NET обновляется, чтобы распознавать это;
- VB
Object
будет использовать только кэширование DLR и методов, если объект реализует IDynamicMetaObjectProvider
;
- Типы BCL и Framework не реализуют
IDynamicMetaObjectProvider
, использование Object
для таких типов или ваших собственных типов вызовет классическое не кэшированное позднее связывание VB.NET.
Справочная информация: подробное описание того, почему кэширование с поздним связыванием может помочь производительности кода VB
Некоторые люди (среди которых Ганс Пассант, см. Его ответ) могут задаться вопросом, почему кэширование или неэширование в позднем связывании может иметь значение На самом деле, это имеет большое значение, как в VB, так и в других технологиях позднего связывания (помните IQueryInterface
с COM?).
Позднее связывание сводится к простому принципу: учитывая имя и его объявления параметров, переберите все методы этого класса и его родительских классов с помощью методов, доступных через интерфейс Type
(и в VB, метод, свойство и поле могут выглядеть одинаково, что делает этот процесс еще более медленным). Если вы считаете, что таблицы методов неупорядочены, то это легко намного дороже, чем один прямой (т.е. типизированный) вызов метода.
Если бы вы были в состоянии найти метод один раз, а затем сохранить указатель метода в таблице поиска, это значительно ускорило бы этот процесс. Привязка кэшированных методов в DLR идет еще дальше и заменяет вызов метода указателем на реальный метод, если это возможно. После первого вызова он становится на порядок быстрее для каждого последующего вызова (в 200–800 раз быстрее).
В качестве примера того, когда это важно, вот некоторый код, иллюстрирующий эту проблему. В случае, когда каждый класс имеет строковое свойство .Name
, но классы не имеют общего предка или интерфейса, вы можете наивно сортировать списки любого из этих типов, например:
' in the body of some method '
List<Customers> listCustomers = GetListCustomers()
List<Companies> listCompanies = GetListCompanies()
listCustomers.Sort(MySort.SortByName)
listCompanies.Sort(MySort.SortByName)
' sorting function '
Public Shared Function SortByName(Object obj1, Object obj2) As Integer
' for clarity, check for equality and for nothingness removed '
return String.Compare(obj1.Name, obj2.Name)
End Function
Этот код (по крайней мере, похожий) фактически сделал его рабочим с одним из моих клиентов и использовался в часто называемом обратном вызове AJAX. Без ручного кэширования свойств .Name
, уже включенных в списки среднего размера, содержащие менее полумиллиона объектов, код позднего связывания стал настолько заметным бременем, что в конечном итоге он разрушил весь сайт. Было трудно отследить эту проблему, но это история в другой раз. После исправления этого, сайт восстановил 95% ресурсов ЦП.
Итак, ответ на вопрос Ганса «разве вам не о чем беспокоиться» прост: это большая проблема (или может быть), особенно. программистам VB, которые слишком небрежно относятся к позднему связыванию.
В этом конкретном случае, и во многих подобных им, VB.NET 2010, по-видимому, не был обновлен для введения позднего связывания, и как таковое Object
остается злом для незнающих и не должно сравниваться с dynamic
.
PS: проблемы с поздним связыванием очень трудно отследить, если только у вас нет хорошего профилировщика производительности и вы не знаете, как компилятор реализует позднее связывание внутри.