Loom.Fody: Tricky but cool Fody Add-In idea
See original GitHub issueThere is a really cool way of allowing for a range of property modifications similar to the Add-Ins PropertyChanged, PropertyChanging and probably AutoDependencyProperty - built with one, very generic Fody Add-In.
The idea is to allow any property implementation defined in the modified assembly be woven in to replace the existing one by writing them as value types implementing interfaces.
As is perhaps well-known among you folks, C# interfaces, C# value type and C# generics come together in a positive twist of .NET goodness: If a value type is used as a type parameter in some generic type, method calls to methods on the value type (through an interface) are not virtual and there’s no boxing involved.
Let me give an example. The class below defines a concrete property implementation.
public interface IPropertyImplementation<ValueInterface, Value>
where Value : ValueInterface
{
Value Get(Object self);
void Set(Object self, Value value);
}
public struct MyPropertyImplementation<Value, OriginalImplementation>
: IPropertyImplementation<IComparable<Value>, Value>
where Value : IComparable<Value>
where OriginalImplementation : IPropertyImplementation<IComparable<Value>, Value>
{
public OriginalImplementation originalImplementation;
public Value Get(Object self)
{
Logger.Log($"Object {self} providing a value.");
return originalImplementation.Get(self);
}
public void Set(Object self, Value newValue)
{
var oldValue = originalImplementation.Get(self);
Logger.Log($"Object {self} receiving new value, which is {(oldValue.CompareTo(newValue) < 0 ? "greater" : "less or equal")}.");
originalImplementation.Set(self, newValue);
}
}
Our yet-to-be-written Add-In would take MyPropertyImplementation and use it to actually implement the properties of certain types (exactly which is a matter of configuration and taste and should not matter here).
The cool thing here is that the call to originalImplementation.Get(self) will in fact not be late-bound (and it’s not boxed either), but an early-bound direct call - the fastest there is. The original implementation is probably even inlined when the optimizer is on.
It’s one trick Java can’t do.
(It works that way even when one creates types at run-time, although not any more with .NET native. But I’m digressing…)
Above implementation can only be used on properties of specific type though: We decided that they all have to be IComparable. That’s why we can use that in above implementation.
Now let’s say this is the type to be rewoven:
public class ClassToHaveItsPropertiesModified
{
public Decimal Decimal { get; set; }
public Int32 Int32 {
get {
return (Int32)Decimal;
}
set {
Decimal = Int32;
}
}
}
Then this would be what the weaver makes of it:
public class ClassThatHadItsPropertiesModified
{
TheImplementationWrappingDecimalAccessors decimalAccessors; // explained below
public MyPropertyImplementation<
Decimal,
TheImplementationWrappingDecimalAccessors
>
decimalImplementation;
public ClassThatHadItsPropertiesModified()
{
decimalImplementation.originalImplementation = decimalAccessors;
}
public Decimal Decimal {
get {
return decimalImplementation.Get(this);
}
set {
decimalImplementation.Set(this, value);
}
}
// same for int
// ...
The TheImplementationWrappingDecimalAccessors type is created by the weaver and provides access to the previous getter and setter methods so the new implementation can call down to them.
This gives a way to sort-of “weave IL without explicitly doing IL”.
I’m a bit in love with this idea.
(The sample here is a bit too simple though. For a PropertyChanged, for example, we also need to mix in a part that has the event implementation and can be accessed by the property implementations. I put up a more complete picture as a gist, although I think it’s fairly straight-forward how that would go.)
Alas, I’m not at all familiar with Cecil and fear this gets me too much off on a tangent. So I wanted to at least put it up for debate.
(Background: I was toying with the idea to bring a dependency tracking implementation, Moldinium, to Fody to allow for dependency-tracked properties. And since I’m me, I can’t help getting distracted on every step.)
I also apologize for being off-topic here, I’m not sure where else I would raise this.
Issue Analytics
- State:
- Created 6 years ago
- Comments:10 (4 by maintainers)

Top Related StackOverflow Question
Oooh, be very careful about that. I have a number of Fody plugins that were just ideas I had that people now use, and want me to support, even if I never used them myself.
No worries.