Bix Updates: Mixin via Cloning and Fody
Bix now supports C# interface-based mixins on the master branch. I am currently working on a feature branch where the mixer functionality has been spun off into a new project called Bix.Mixers.Fody.
That's pretty much what I have to say. Feel free to read on for the long version :-)
Bix Mixin Functionality
At last checkin, my concern with was about field initialization and how to handle constructors. In looking to solve that problem, I couldn't figure out good way to make field initialization (and constructor logic, in general) controllable within the strategy of decompiling a reference assembly and manually creating matching IL.
So I pulled the trigger on a big change, a change that I had been avoiding because of the daunting amount of IL level work and because I just wasn't certain that it would work. There were hard problems to solve. For example, if I'm cloning a method Source.GetFoo()
, and its return value is of type Source
, then the intent is likely for the cloned Target.GetFoo()
to return type Target
. How can that be detected and replaced. And that's an easy example since a method signature is well-defined. What about if type Source
is referenced as the operand of and IL operation? Operands are all represented as object
. Should the code check whether the operand is a type? What if it's a property of 'Source' that's being referenced?
I wanted to focus on the framework mixins themselves, and this was so much plumbing. So, yeah, I was trying avoid this.[1][2]
I started in November 2013. My family and I were still living in Denmark at the time. I was interrupted in December because my wife and children flew home just before Christmas.
My best-laid January plans were to work on Bix non-stop. That didn't happen. Instead, all of my energy went into getting as much work as possible done during my final days at Statistics Denmark and preparing to move. These things'll wear a guy out. I picked up Bix from time to time, but I mostly split my free time between video calls with my family and watching episodes of Burn Notice.
Throughout all of this time, even when I wasn't working on Bix code cloning, I was thinking about it. Even worn out, 3 episodes into Bruce Campbell-land, it would be sitting at the back of my mind. From time to time, I'd pull out the laptop, attack it, hit a wall, and back off. I would come back later, try a solution, hit a wall, and back off. I'd come later, delete all of my changes, try again, and back off yet again.
I flew out of Copenhagen on the morning of February 1, 2014. After a period of settling in, I was able to put some real time into Bix. Given the pregnancy status of my wife, the period of productive Bix work was limited. On February 28, our new beautiful baby girl disembarked from the mothership.
In the midst of all of this, somehow I got code cloning working. It's not yet feature complete, but it's usable, and the concept has been proven. It supports nested types, it redirects all references to types/properties/fields/etc within the root source type to the target version's of that member. It's useful enough that I decided to spin it off into it's own project.
Bix.Mixers.Fody
The Fody README states:
Manipulating the IL of an assembly as part of a build requires a significant amount of plumbing code. This plumbing code involves knowledge of both the MSBuild and Visual Studio APIs. Fody attempts to eliminate that plumbing code through an extensible add-in model.
I initially wrote the mixing functionality to run as a stand-alone executable with the full knowledge (and a code TODO stating as much) that it would need to change. The ideal solution would be to have apply the mixing (or "code weaving" as post-compile IL manipulation is known) as a build step. Fody provides a framework for exactly this. Perfect :-)
The plan is to pull Bix.Mixers.Fody into its own project, make it available via NuGet, and make Bix include it as a NuGet dependency. I have a "Fodify" feature branch in Bix where I am doing just that. I am currently working directly against the master branch of the Bix.Mixers.Fody project.
Although the mixin functionality is not yet "feature complete" (generic support and event support are notably absent), I plan to make the first official pre-release as soon as the code runs correctly through Fody with fully documented code and a full set of tests. After that, I have about 13 TODOs in the code marking either missing features or research points to examine more closely for correctness, some of which I'll address quickly, and others I'll address as they become roadblocks in the future.
After the mixin command, my next task is planned to be some sort of projection weaver, so that, for example, a rich business object can project properties to create a simple POCO or DTO.
[1] PostSharp politely but firmly declined my request for a free open-source project license or I could have avoided all of this manual code weaving. At the time, the code base was nearly non-existent, so I can't say I blame them. It does illustrate a chicken/egg scenario for this type of project. At this point, I'm really enjoying the project, so I'm content with how it has turned out.
[2] At the suggestion of a colleague, I looked into Fody for a mixin plugin before I started this project. At the time, there was none. There is now a Fody mixins plugin. I've already built my own to perfectly fit my needs, however, so I won't be switching.