Pull to refresh

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

Reading time 8 min
Views 29K
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) я разбил плагины по категориям полезные/бесполезные*, но тут я себе такого не позволяю, так что всё списком по алфавиту:

Anotar
https://github.com/Fody/Anotar
Заменяет вызов одного метода на создание/резольвинг логгера и его вызов. Имеет несколько встроенных интеграций с основными логгинг системами. Полезность сомнительна, но тут на вкус и цвет.

AssertMessage
https://github.com/Fody/AssertMessage
Assert.AreEqual(expectedCustomer.Money, actualCustomer.Money); // => 
Assert.AreEqual(expectedCustomer.Money, actualCustomer.Money, "Assert.AreEqual(expectedCustomer.Money, actualCustomer.Money);"); 

Почему бы и нет. Если Вы пользуетесь Assert — ами и не против подождать несколько лишних секунд при билде пока этот плагин дописывает за Вас строчки.

AsyncErrorHandler
https://github.com/Fody/AsyncErrorHandler
Заключает async в try-catch блок в котором выполняет
AsyncErrorHandler.HandleException(exception);
Мы не пользуемся, но выглядит заманчиво, один из кандидатов на более плотное тестирование и внедрение при необходимости.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Articles