Исключение классов, созданных через контейнер IOC, из предупреждения NDepend

Мои отчеты NDepend предупреждают, что «нестатические классы должны быть созданы или превращены в статические». Большинство классов в возвращаемом списке регистрируются через мой контейнер IOC (Unity) и создаются моей инфраструктурой IOC во время выполнения.

Учитывая, что NDepend выполняет статический анализ, он не будет знать о создании экземпляра во время выполнения. Я надеюсь, что можно настроить CQL, чтобы он знал о моем контейнере.

Это стандартный запрос, который выполняет NDepend:

warnif count > 0
from t in JustMyCode.Types
where  t.IsClass &&
//!t.IsPublic &&   // if you are developping a framework, 
                   // you might not want to match public classes
  !t.IsStatic && 
  !t.IsAttributeClass && // Attributes class are never seen as instantiated
  !t.DeriveFrom("System.MarshalByRefObject".AllowNoMatch()) // Types instantiated through remoting infrstructure

// find the first constructor of t called
let ctorCalled = t.Constructors.FirstOrDefault(ctor => ctor.NbMethodsCallingMe > 0)

// match t if none of its constructors is called.
where ctorCalled == null
select new { t, t.Visibility }

Могу ли я настроить этот запрос, чтобы исключить классы, на которые есть ссылки в моей регистрации контейнера IOC?


person kiprainey    schedule 27.01.2014    source источник


Ответы (1)


Действительно, вы можете проголосовать за поддержку NDepend IoC Framework на сайт NDepend User Voices. Это функция, которая будет реализована в будущем.


На данный момент вы можете справиться с этим с помощью атрибута. Создайте в своем коде класс атрибутов, например, с именем MyProduct.IoCInstantiatedAttribute.

Затем вы можете пометить все свои классы, созданные исключительно IoC, с помощью этого атрибута. Поскольку этот атрибут необходим только для сборки DEBUG (та, которая анализируется NDepend), я бы посоветовал использовать условный синтаксис DEBUG.

#if DEBUG
[IoCInstantiated]
#endif
class MyClass { ... }

Наконец, вам просто нужно добавить && !t.HasAttribute("MyProduct.IoCInstantiatedAttribute") в соответствующие правила и вуаля!

Кроме того, вы также можете написать правило, чтобы убедиться, что классы, имеющие этот атрибут, нигде не создаются. Таким образом, вы сохраните чистоту использования этого атрибута!

// <Name>Types tagged with attribute IoCInstantiated must not be instantiated elsewhere</Name>
warnif count > 0 
from t in Types 
where t.HasAttribute ("MyProduct.IoCInstantiatedAttribute") 
let methodsInstiatingMe = Application.Methods.ThatCreateA(t)
where methodsInstiatingMe.Any()
select new { t, methodsInstiatingMe }

Лично я обнаружил, что использование такого атрибута — это здорово, потому что он также документирует код. Когда разработчик просматривает такой класс, он может с первого взгляда получить эту важную часть информации (созданную исключительно через IoC).

person Patrick from NDepend team    schedule 28.01.2014
comment
Спасибо, Патрик, это сработало. Я добавил атрибут в свой проект, соответствующим образом обновил запросы, а также добавил защитный запрос. Это помогло уменьшить шум в моих отчетах. Я среди тех, кто хотел бы, чтобы NDepend стал поддерживать IOC. Однако в предложении, указанном в предоставленной вами ссылке, конкретно упоминается синтаксический анализ XML для идентификации регистраций IOC. Хотя это потенциально полезно, большинство регистраций контейнеров, с которыми я сталкиваюсь, происходят в коде, а не в конфигурации. Если бы NDepend мог распознавать регистрацию контейнеров в коде, это было бы полезнее. - person kiprainey; 28.01.2014
comment
Чтобы дополнить то, что сказал @Patrick, я также счел полезным исключить контроллеры MVC и Web API. Их можно исключить без добавления дополнительного атрибута: !t.DeriveFrom("System.Web.Http.ApiController") && // Skip api controllers, which are instantiated via the framework !t.DeriveFrom("System.Web.Mvc.Controller") && // Skip mvc controllers, which are instantiated via the framework - person kiprainey; 28.01.2014