.NET IL Weaving for those who know nothing about .NET IL Weaving

Cover

Introduction 🎉

I’m starting this series for two main reason: One is because writing about a subject that I’m currently studying helps me learn it much better. Second, which is probably the most important reason, is because there are very few articles about this topic. The ones that exist aren’t very thorough in explaining the steps that one needs to understand weavers fully. So here I am, trying to fill those gaps.

Whether you heard about weaving before or not, this article was written under the assumption that you know literally zero about it. I only ask you to know some C# and be willing to try new stuff. Here you will learn the basics on how to consume weavers, but by the end of the series we’ll be writing our own weavers and peeking into .dll files.

Weaving? 🤔

Weaving is a concept that tends to scare people. It’s the act of manipulating a compiled .dll file and injecting additional instructions in it. This can be used, for example, to reduce the amount of boilerplate in your codebase, by making repetitive tasks be done by a computer instead of by humans that will, inevitably, make copy&paste mistakes®.

The reason weaving scares people is because messing with a .dll feels a bit like saying “Hey, I know more about IL than the Roslyn team”, a statement that’s almost always false (Jon Skeet is one obvious exception). I get this concern (I felt like that at first), but although the approach feels fragile and the idea itself might sound like a massive overkill, the current state of the tooling for weavers is so good and simple to use that you will regret not using it before!

Just for the sake of proving my commitment to weavers, in the past 3 years I don’t recall having shipped a single application that did not use them (the one I’m currently working one are Toggl’s mobile apps, which are OSS and can be found here). Weavers are also used by Realm, the mobile first database, to inject native calls to C++ code in every property of classes that inherit from RealmObject. So how do I get started‍? 🤓

By far the most common usage weaving is removing the INotifyPropertyChange boilerplate. When implementing this interface, you need to ensure that each and every single one of your properties:

Does some equality comparison
Early return if the value didn't change
Set the value of the backing field
Notify that the property has changed

This means that you can’t make use of auto properties, the C# feature that removes the need of managing a backing field, and that your properties will look like this:

namespace NonWoven
{
    //BaseViewModel implements INotifyPropertyChanged
    public sealed class LoginViewModel : BaseViewModel
    {
        private bool _isLoading;
        public bool IsLoading
        {
            get => _isLoading;
            set
            {
                if (_isLoading == value) return;
                _isLoading = value;
                RaisePropertyChanged();
            }
        }

        private string _email;
        public string Email
        {
            get => _email;
            set
            {
                if (_email == value) return;
                _email = value;
                RaisePropertyChanged();
            }
        }

        private string _password;
        public string Password
        {
            get => _password;
            set
            {
                if (_password == value) return;
                _password = value;
                RaisePropertyChanged();
            }
        }
    }
}

11 Lines of code for each property? Nopeđź™…

Weaving to the rescue ⛑

So we identified a task that is both recurring and tedious. The code is very much the same and we’ll catch ourselves copy/pasting this more often than not. What should we do next? Use weavers!

For such, we’ll be using Fody. It’s a tool that does the all the plumbing needed during the build phases so we don’t have to deal with MSBuild ourselves. Remember when I said that weaving was simple? That’s because Fody got your back.

Fody on its own, however, does nothing. It only provides the means for us to consume add-ins. Later in the series we’ll see how we can create our own add-ins, but for now we’ll settle with consuming the well tested and widely used PropertyChanged plugin.

Since Fody uses MSBuild, it works on Visual Studio for both Windows and Mac. All you got to do is install the PropertyChanged.Fody NuGet package. It’ll add the Fody package as a dependency and also add a FodyWeavers.xml file to your project. Open this file and make sure that it contains the name of the plugin you want to use, like this:

<?xml version="1.0" encoding="utf-8" ?>
<Weavers>
    <PropertyChanged />
</Weavers>

Et voilĂ ! You simply installed a NuGet package and verified that an XML file had a word in it and, in return, your 11-loc-per-property ViewModel now looks like this:

namespace Woven
{
    //BaseViewModel implements INotifyPropertyChanged
    public sealed class LoginViewModel : BaseViewModel
    {
        public bool IsLoading { get; set; }

        public string Email { get; set; }

        public string Password { get; set; }
    }
}

Pretty neat, huh?

That looks great, but does it work? 🙄

As previously stated, weaving is a technique that’s widely used among .NET developers. The PropertyChanged package has almost half a million downloads and Realm (which also relies on Fody) has almost 100K.

If usage statistics and companies using Fody are not enough to change your skepticism towards weaving, stay tuned for the next two articles, where we’ll go deeper into what CIL looks like and how you too can manipulate compiled .dlls to do what you want.

In the meantime, explore Fody yourself! Install PropertyChanged.Fody in a test project, read its docs, check other plugins and feel free to reach out to me on twitter if you need help with anything!