Fody и его плагины

imageС выходом Roslyn разговоры о том, что скоро кода можно писать будет меньше вспыхнули с новой силой. Сегодня я расскажу немного о другом подходе как писать меньше кода и соответственно делать меньше ошибок — расскажу о Fody. На хабре упоминание нашёл только вскользь в рамках решения како-то проблемы. Для того, чтобы заинтересовать читателя, ещё не решившего стоит ли тратить своё время на данный текст отмечу, что популярный NotifyPropertyWeaver переехал на Fody и с помощью Fody можно делать всякие там классные AOP.Итак, Fody — инструмент для постобработки .net сборок с целью внедрения в них своего IL кода через Cecil.Emit. Fody представляет из себя msbuild таску которая имеет конфигурационный файл в каждом из проектов, для которых будет запущена. Вот такая строка будет добавлена в каждый ProjectName.project файл

<Import Project="Fody.targets" /> Всю работу по внедрению IL делают Fody плагины, перечисленные в конфигурационном файле. <?xml version="1.0" encoding="utf-8" ?> <Weavers> <SuperPluginName /> </Weavers> Максимально ничего не делающий плагин можно себе представить, как: public class ModuleWeaver { // Можно писать в MSBuildLog public Action<string> LogInfo { get; set; } // Экземпляр Mono.Cecil.ModuleDefinition для текущей сборки public ModuleDefinition ModuleDefinition { get; set; } public void Execute() { } } Если возникает вопрос зачем Fody вообще нужен, то скажу лишь что это очень удобно. Он инсталлируется через nuget и написав свой плагин можно просто указать его как зависимость. Главное понять, как Fody будет искать этот плагин и создать правильную структуру файлов и папок в packages и всё — вы уже переписываете IL в своих сборках like a boss.

Плагины Сам по себе fody не имеет большого смысла, поэтому представляю обзор набора плагинов с официального сайта github.com/Fody/Fody. Описание каждого плагина очень краткое, но я надеюсь достаточное чтобы принять решение стоит ли тратить время на чтение документации. Надеюсь будет полезно. У себя в блоге (alexeysuvorov.com) я разбил плагины по категориям полезные/бесполезные*, но тут я себе такого не позволяю, так что всё списком по алфавиту:Anotarhttps://github.com/Fody/AnotarЗаменяет вызов одного метода на создание/резольвинг логгера и его вызов. Имеет несколько встроенных интеграций с основными логгинг системами. Полезность сомнительна, но тут на вкус и цвет.

AssertMessagehttps://github.com/Fody/AssertMessage

Assert.AreEqual(expectedCustomer.Money, actualCustomer.Money); // => Assert.AreEqual(expectedCustomer.Money, actualCustomer.Money, "Assert.AreEqual(expectedCustomer.Money, actualCustomer.Money);"); Почему бы и нет. Если Вы пользуетесь Assert — ами и не против подождать несколько лишних секунд при билде пока этот плагин дописывает за Вас строчки.AsyncErrorHandlerhttps://github.com/Fody/AsyncErrorHandlerЗаключает async в try-catch блок в котором выполняетAsyncErrorHandler.HandleException(exception);Мы не пользуемся, но выглядит заманчиво, один из кандидатов на более плотное тестирование и внедрение при необходимости.

Bix.Mixershttps://github.com/rileywhite/Bix.Mixers.FodyИнтеграция с BixMix. Сам BixMix похоже не так давно стартанул и информации очень мало, так что пожелаем парням удачи и пойдём дальше.

Caselesshttps://github.com/Fody/CaselessДля строк заменяет == на string.Equals с соответствующим StringComparison. Очень сомневаюсь что хочу чтобы за меня это делал IL инжектор.

Catel.Fodyhttps://github.com/Catel/Catel.FodyДелает DependencyProperty из обычных если класс унаследован от DataObjectBase или ViewModelBase. Как я понял Catel позиционирует себя как фреймворк для бизнеса поверх .net framework. Если пользуетесь Catel, то наверное будет удобно.

Commander.Fodyhttps://github.com/DamianReeves/Commander.FodyРеализует ICommand для MVVM. В непонятном состоянии, документация не дописана.

Costurahttps://github.com/Fody/CosturaДля фанатов ILMerge. Склеивает зависимые сборки в одну.

FodyDependencyInjectionhttps://github.com/jorgehmv/FodyDependencyInjectionОчень странный плагин. Резольвит зависимости из одного из 3-х IoC контейнеров Ninject, Autofac или Spring.Net в свойства объектов минуя конструктор. Не стал разбираться что там и как внутри, потому что посыл изначально неправильный. Я считаю, что все зависимости должны быть объявлены как параметры конструктора, а иначе черт ногу сломит разбираться в коде.

EmptyConstructorhttps://github.com/Fody/EmptyConstructorДобавляет пустой конструктор к классу если он не определён. Сомнительно полезен.

EmptyStringGuardhttps://github.com/thirkcircus/EmptyStringGuardПереписывает сеттеры и публичные методы принимающие строки, добавляет проверку на то, что строка не пустая. Если строка может быть пустая, то её можно пометить атрибутом AllowEmpty. Возможно некоторые найдут полезным, но меня больше беспокоят null чем пустые строки.

EnableFaking.Fodyhttps://github.com/philippdolder/EnableFaking.FodyЕщё один «антиплагин» (первый был FodyDependencyInjection), всем классам добавляет virtual для всех мемберов публичных классов (на самом деле там ряд условий). Предполагается что это удобно для тестирования и перед продакшеном это нужно выключать. Если нужно использовать этот плагин, значит с дизайном что-то не так.

Equalshttps://github.com/Fody/EqualsДля помеченных объектов реализует методы Equals на основе свойств входящих в объект. Если у Вас куча DTO объектов и правила их сравнения примитивно просты, то возможно это то, что нужно.

ExtraConstraintshttps://github.com/Fody/ExtraConstraintsПозволяет задать delegate, enum и struct ограничения на тип параметр. C# не поддерживает такие ограничения, но в IL они вполне себе валидны. Возможно появятся в следующих версиях С# stackoverflow.com/questions/1331739/enum-type-constraints-in-c-sharp/1331811#1331811.

Fielderhttps://github.com/Fody/FielderКровь кишки и расчленёнка — перефарширует все проеперти в филды. Самый безумный плагин по моему мнению.

Freezablehttps://github.com/Fody/FreezableВо все классы унаследованные от спец интерфейса IFreezable инжектится код, который бросается исключениями на проперти сеттерах после вызова метода Freeze. Мой проеденный f# с его immutability мозг не может себе представить сценарии когда это можно использовать вместо объектов где readonly проперти задаются в конструкторе и не имеют свойств, но возможно будет полезен.

InfoOfhttps://github.com/Fody/InfoOfПредоставляет methodof, propertyof и fieldof, но конечно никакой магии и всё нужно писать строками, которые потом перепишутся в соответствующие IL команды (да, methodof, propertyof и fieldof есть в IL). На любителя.

Ionadhttps://github.com/Fody/IonadЗаменяет все вызовы методов статических классов на Ваши имплементации с такими же сигнатурами. Наверное, полезно для тестинга, но Fake (бывший moles) делает всё лучше.

Janitorhttps://github.com/Fody/JanitorАвтоматически реализует IDisposable для всех классов унаследованных от IDisposable. Использует volatile int для определения что Dispose уже был вызван. Если Вы разделяете взгляд автора плагина на то, как должен быть реализовал IDisposable, то это неплохой плагин.

JetBrainsAnnotationshttps://github.com/Fody/JetBrainsAnnotationsJet Brains и тут подсуетился, молодцы чё.

MethodCachehttps://github.com/Dresel/MethodCacheМемоизация методов помеченных аттрибутами. Реализация кеша оставлена нам, что конечно радует. С удовольствием посмотрю поближе и потестирую если возникнет подходящая задача.

MethodDecoratorhttps://github.com/Fody/MethodDecoratorДекорирует методы помеченные атрибутами. Позволяет поймать момент входа в метод, выхода из него и эексепшен если произошёл. Широко используем в проекте, правда не оригинальную, а мой форк, который я допиливал под нужды проекта и заодно заимплементил несколько пожеланий из обсуждения оригинального плагина. Умеет захватывать параметры передаваемые в метод. Я про него писал. Не стесняйтесь файлить в Issues на гитхабе, постараюсь оперативно фиксить/расширять при возможности.

MethodTimerhttps://github.com/Fody/MethodTimerОблегчённая версия MethodDecorator, только меряет время которое заняло выполнение метода. Гадит в Debug или в логгер, который Вы ему предоставите. Возможно полезен, хотя MethodDecorator на мой взгляд удобнее.

Mixins.Fodyhttps://bitbucket.org/skwasiborski/mixins.fody/wiki/HomeМножественное наследование через примеси. Альтернатива Castle's dynamic proxy mixins. Я не поборник морали, так что вполне себе допускаю что вернусь к этому плагину, как только .net загонит меня в необходимость наследоваться и от класса Framework и от моего класса. Действительно было такое один раз.

ModuleInithttps://github.com/Fody/ModuleInitСобеседуя кандидатов я выяснил для себя то, что не все .net программисты в курсе, что сборка содержит в себе модули. Это плагин позволяет задать конструктор для модуля. Для тех, кто понимает.

Mutable.Fodyhttps://github.com/ndamjan/Mutable.FodyАнтипод к Freeze. Делает иммутабельное мутабельным, правда уже после того как компилятор всё скомпилировал. Имеет смысл если в F# нужно десериализовать из XML, но Newton.Json уже добавил нормальную десериализцию для immutable f# типов, так что не вижу большого смысла, только если не legacy xml.

NullGuardhttps://github.com/Fody/NullGuardПервый в очереди на использование. Генерирует проверки на null если явно неуказано что null возможен. По моему мнению такие вещи просто необходимы в языках, допускающих null.

Obsoletehttps://github.com/Fody/ObsoleteПозволяет использовать Obsolete аттрибут эффективно. Можно задать версию с которой при обращении к Obsolete будут происходить ошибки компиляции и версию сборки начиная с которой она не скомпилируется с классом помеченным таким атрибутом. Очень удобно я думаю.

PropertyChangedhttps://github.com/Fody/PropertyChangedБывший NotifyPropertyWeaver. Для тех, кто не знаком – этот плагин добавляет оповещение (вызов) PropertyChanged эвента для всех сеттеров пропертей объектов, унаследованных от INotifyPropertyChanged или помеченных атрибутов. Совершенно незаменимая вещь если вы хоть раз пытались писать под WPF и его подмножества. Строго рекомендую к использованию если у вас есть UI на WPF.

PropertyChanginghttps://github.com/Fody/PropertyChangingТоже самое, но для интерфейса INotifyPropertyChanging.

Publicizehttps://github.com/Fody/PublicizeДелает приватные поля публичными «скрытыми». Мотивацию автор не стал уточнять, оставим это на его совести.

RemoveReference.Fodyhttps://github.com/icnocop/RemoveReference.FodyМожно указать в атрибуте уровня сборки какие сборки вы хотите удалить из References после билда. Насколько я понял таким шаманством автор предлагает лечить вот этот баг connect.microsoft.com/VisualStudio/feedback/details/779370/vs2012-incorrectly-resolves-mscorlib-version-when-referencing-pcl-assembly. Он всё ещё открыт.

Resourcerhttps://github.com/Fody/ResourcerОблегчает доступ к ресурсам сборки позволяя не писать AssemblyName. Отличный вариант для сборок с тестами. В очереди на применение в самое ближайшее время.

Scalpelhttps://github.com/Fody/ScalpelВырезает тестовые методы и классы из сборок с кодом по конвеншену или по атрибуту. Судя по всему, Саймон (автор Fody и большинства плагинов) практикует тестирование «не отходя от кассы». Мне трудно представить мотивацию, но конечно это не самый безумный плагин, хотя уверенно входит в топ 5.

Stamphttps://github.com/Fody/StampДобавляет в AssemblyVersionInformation хешик последнего git коммита. На вкус и цвет.

Stilettohttps://github.com/benjamin-bader/stilettoЕщё один вариант IoC контейнера. Может похвастаться завидной всеядностью потому как работает там, где нет Reflection.Emit. Если пишете на Xamarin под iOS, то посмотрите в эту сторону, возможно это не даст совсем загрустить без IoC.

ToStringhttps://github.com/Fody/ToStringКак и Equals генерирует код на основе полей и как Вы, наверное, уже догадались по название генерирует метод ToString. Если очень не хочется писать ToString для отладки, то это нужный плагин, но польза сомнительна, я не могу вспомнить, когда переопределял ToString не в отладочных целях.

Usablehttps://github.com/Fody/UsableЗаворачивает в using локальные переменные имплементирующий IDisposable. Пишите лучше ручками, надёжнее и понятней.

Validarhttps://github.com/Fody/ValidarПозволяет встроить реализацию IDataErrorInfo и INotifyDataErrorInfo в класс, реализующий INotifyPropertyCanged. Во все классы, помеченные атрибутом InjectValidation будет заинжекчена реализация IDataErrorInfo и INotifyDataErrorInfo из класса с именем ValidationTemplate конструктор которого принимает INotifyPropertyChanged. Если пишите под WPF – обязательно посмотрите, возможно это именно то, что нужно.

Visualizehttps://github.com/Fody/VisualizeРасставляет DebuggerDisplay атрибуты и если класс содержит поля, то генерирует «правильный» код который позволяет смотреть значение полей в режиме дебаггера. Интересно, что для последовательностей генерируется прокси класс. Очень интересная возможность, но я не очень люблю сидеть в отладчике предпочитая ему юнит тесты, так что платить временем сборки проекта за возможность всё посмотреть я бы не стал.

Это всё. Надеюсь я сэкономил Вам несколько часов блуждания по гитхабу в поисках фоди плагинов. Спасибо за внимание.

*Все плагины я оценивал исходя из глубин своего невежества, так что прошу не судить строго, а оппонировать в комментариях.

© Habrahabr.ru