Внедрение зависимостей в .Net без вызовов виртуальных методов? - PullRequest
2 голосов
/ 26 января 2010

Я думал о том, возможно ли применить шаблон DI, не неся при этом затрат на виртуальные вызовы методов (которые, согласно моим экспериментам, могут быть в 4 раза медленнее, чем не виртуальные вызовы). Первая идея, которая у меня была, заключалась в том, чтобы сделать внедрение зависимостей с помощью обобщений:

sealed class ComponentA<TComponentB, TComponentC> : IComponentA 
    where TComponentB : IComponentB
    where TComponentC : IComponentC
{ ... }

К сожалению, CLR по-прежнему выполняет вызовы методов через интерфейсы, даже когда конкретные реализации TComponentB и TComponentC определены как параметры универсального типа, а все классы объявлены как закрытые. Единственный способ заставить CLR выполнять не виртуальные вызовы - это изменить все классы на структуры (которые реализуют интерфейсы). Однако использование struct не имеет смысла для DI и делает проблему ниже еще более неразрешимой.

Вторая проблема с вышеуказанным решением заключается в том, что он не может обрабатывать циклические ссылки. Я не могу придумать, как с помощью кода на C # или путем создания деревьев выражений обрабатывать циклические ссылки, потому что это повлечет за собой бесконечно повторяющиеся универсальные типы. (.Net поддерживает универсальные типы, ссылающиеся на себя, но, похоже, не обобщает этот случай.) Поскольку только структуры могут заставить CLR обходить интерфейсы, я не думаю, что эта проблема вообще решаема, потому что циклические ссылки между структуры могут вызвать парадокс.

Есть только одно решение, которое я могу придумать, и оно гарантированно сработает - генерировать все классы с нуля во время выполнения, возможно, основываясь на скомпилированных классах в качестве шаблонов. Хотя на самом деле это не идеальное решение.

У кого-нибудь есть идеи получше?

Редактировать: В отношении большинства комментариев, я думаю, я должен сказать, что это подано в «чистом интеллектуальном любопытстве». Я спорил, стоит ли спрашивать об этом, потому что я понимаю, что у меня нет конкретного случая, в котором необходимо. Я просто думал об этом ради интереса и задавался вопросом, сталкивался ли кто-нибудь еще с этим раньше.

Ответы [ 3 ]

4 голосов
/ 26 января 2010

Типичный пример попытки полностью перегрузить что-то на мой взгляд. Просто не ставьте под угрозу свой дизайн, потому что вы можете сэкономить несколько десятков миллисекунд - даже если это так.

Вы серьезно предполагаете, что из-за инструкций callvirt ваше приложение оказывается настолько значительно медленнее, что пользователи (те люди, для которых вы пишете приложение) заметят какую-либо разницу - при всех? Я очень сильно сомневаюсь.

3 голосов
/ 26 января 2010

Это сообщение в блоге объясняет, почему вы не можете оптимизировать виртуальный вызов.

2 голосов
/ 26 января 2010

В то время как инструкция callvirt занимает больше времени, это обычно делается, потому что она обеспечивает дешевую проверку null для CLR перед вызовом метода.callvirt не должно занимать значительно больше времени, чем инструкция call, особенно с учетом проверки null.

Вы обнаружили, что вы можете значительно улучшить производительность своего приложения, создавая типы (либо structs)* или классы со статическими методами), которые позволяют вам гарантировать, что компилятор C # будет выдавать call инструкций вместо callvirt инструкций?

Причина, по которой я спрашиваю, заключается в том, что мне интересно, собираетесь ли вы создаватьне поддерживаемая кодовая база, которая является хрупкой и трудной в использовании просто для решения проблемы, которая может существовать или не существовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...