Introduction
The LinFu
Framework is a collection of a few things that I've always wanted to do in .NET, but unfortunately, there weren't any existing implementations that matched all of my needs. So, like any other curious programmer, I set out to write my own library and this is the result. I can ramble on and on about it, but this picture should give you a general idea of what LinFu
does and where this series of articles is going:
Note: The word LinFu
(Pronunciation: LINN-FOO) is actually an acronym that means "Language INdependent Features Underneath [.NET]." What started as simple tinkering into dynamic proxies and Reflection.Emit
four years ago slowly evolved into a personal project in extending existing .NET languages without changing their respective syntaxes. This entire framework is a culmination of those years of my own personal research and, after some deliberation, I've decided to license this whole project under the terms of the LGPL license. This means that everyone will be free to use the library without royalties as long as it adheres to the terms of that license. If you are going to use this in your own commercial projects, then I would absolutely love to get some constructive commercial feedback (and a few professional references wouldn't hurt either).
If there are any features that you think should be added (or any features you want to add yourself), just send me a copy of it so that I can look at it and merge it into the codebase that I currently have with me. Anyway, let's go back to the article…
Language Independent?
LinFu
, in its most basic form, is nothing but a managed DLL library that is compiled into IL. Since anything written in IL can be used by any .NET language, all the features of LinFu
that I will be showing in the following articles can be consumed by any .NET language. Using this rationale, LinFu
extends languages like VB.NET and C# without affecting their respective syntaxes. It supports the following features:
Dynamic Proxies
LinFu
has its own proxy generator, which even predates other more prominent implementations such as CastleProject's Dynamic Proxy and Castle DynamicProxy2. This version of LinFu
DynamicProxy has supported generics ever since the VS2005 release and, based on my current benchmarks (which will be discussed in this article), it consistently outperforms Castle's implementation by a factor of at least 200%. In short, LinFu
's Dynamic Proxy is lean, mean and very, very fast.
Duck Typing and Late Binding
Dynamic languages such as Ruby and Python (and to some extent, VB.NET) have the amazing ability to call methods at runtime without knowing exactly which methods they will be using at compile time. Furthermore, those take that concept even further and actually "infer" which method should be called based on the arguments that are passed to the method at runtime (aka "Duck Typing"). It would be nice if there were a way to do that natively in C# (2.0), but unfortunately, that's not entirely possible... unless you use LinFu
, of course! LinFu
does some mind-bending tricks with the C# syntax to make it work and, later in the series, I'll show you how it all works behind the scenes.
Ruby-style Mixins
Dynamic languages have the ability to seamlessly and dynamically modify their classes at runtime so that each class can practically add and subtract methods (and even add other classes and interface implementations) to and from each class implementation. Believe it or not, I've found a way to implement the same type of dynamic mixins in both C# and VB.NET and still be able to adhere to the strongly-typed rules of each of both languages! (Well, maybe not VB.NET, since sometimes it can be loosely typed, but I digress). With LinFu
, you can incrementally build an object's implementation at runtime just as easily as one can incrementally build an SQL string. Want to dynamically implement an interface at runtime, but don't have a class that implements it at compile time? No problem. LinFu
can incrementally stitch methods together to form one cohesive interface implementation, all at runtime.
Delegates with Lambda Arguments (aka, "Currying")
While languages such as C# 3.0 and the upcoming version of VB.NET have support for defining Lambda "Expressions," one feature that I've always wanted to have is the ability to take any delegate and actually hard-bind (or close) one or more of the delegate parameters to a specific arbitrary value. In other words, this feature allows you to "simulate" delegate calls by hard-wiring some (or all) of the arguments passed to a delegate when an event is fired. In other words, LinFu
makes it very easy to mock events.
Universal Event Handling
One of the biggest problems in writing an application that uses the MVC pattern (or the MVP pattern) is finding a uniform way to have the controller handle events that are fired from the Presentation/View without knowing "a priori" the signature of those events at compile time. LinFu
can actually attach itself to any event fired on any object at runtime, regardless of the delegate signature that event might be using.
A Very, Very Simple IoC Container
Imagine that you had an Inversion of Control (or Dependency Injection) container that didn't rely on an external configuration file (such as an XML file) to assemble itself. Furthermore, suppose that the only "configuration" that you would have to do would involve less than a few lines of code and a simple XCOPY
operation in order to get everything up and running. Does it sound too simple? Well, seeing is believing and in Part IV, I'll do my best to make you a believer.
Design by Contract
There have been quite a few attempts at creating a DbC Framework in .NET (and even in Java, with JContract) such as eXtensible C#, Kevin McFarlane's DbC Framework and the like, but few of them have been able to effectively emulate the Eiffel language's DbC mechanism without tying their respective implementations to their particular language (in the case of XC#) or cluttering their domain methods with numerous precondition, postcondition and invariant checks (as is the case with McFarlane's library). LinFu
allows you to transparently inject preconditions, postconditions and invariants into your code at runtime, regardless of whether or not you actually have access to the source code of the library you wish to inject. Want to wrap System.Data.IDbConnection
in a user-defined contract? No problem, it only takes a single line of code. Want to dynamically generate verifiable contracts at runtime? LinFu
can do that, too. When used in combination with the Simple.IoC
container, it can even inject contracts into your apps while it's still running, all without recompiling your entire application.
As you can see, LinFu
can do quite a few interesting things. In publishing these articles, I hope that I can help a sizeable number of developers out there to write better code through the use of my library. For me, it's always a pleasure to give back to the developer community as a whole and any additional hour that I can spend saving any other developer from having to write more boilerplate code is time well spent. So, without further ado, let's get started!
Background
This article assumes that you're familiar with the concept of dynamic proxies and, for those of you who are interested in figuring out how it all works, I'll do my best to explain it in the next few sections without having to dive into the gory details of Reflection.Emit
. If you're a casual developer, however, you can just browse the next few sections to use the code.
DynamicProxy
This article will show you how to use LinFu
's DynamicProxy
to add "hooks" to your method code so that you can arbitrarily inject new code into your application at runtime. This can be useful if you want to add additional features to your application (such as logging or performance timing), but you don't want to have those additional features to be cluttered across your codebase.
Using the Code
LinFu
's DynamicProxy
library allows you to intercept any method call made to any virtual method in your object instances and replace those methods with your own implementation at runtime. For example:
public class Greeter
{
public virtual void Greet()
{
Console.WriteLine("Hello, World!");
}
}
In this example, we're going to wrap the Greet()
method and we're also going to replace that greeting with "Hello, CodeProject!"
Choose Your Flavor
With LinFu
, there are two styles of interception, as denoted by the following interface definitions:
public interface IInterceptor
{
object Intercept(InvocationInfo info);
}
public interface IInvokeWrapper
{
void BeforeInvoke(InvocationInfo info);
object DoInvoke(InvocationInfo info);
void AfterInvoke(InvocationInfo info, object returnValue);
}
Wrapping the Greeter Object
Depending on what your needs might be, you'll have to implement one of these two interfaces to create your own interceptor. In this case, we're going to implement IInvokeWrapper
so that we can add some additional behavior to the Greeter
class before and after its Greet()
method is called:
public class GreetInterceptor : IInvokeWrapper
{
private Greeter _target;
public GreetInterceptor(Greeter target)
{
_target = target;
}
public void BeforeInvoke(InvocationInfo info)
{
Console.WriteLine("BeforeGreet() called");
}
public object DoInvoke(InvocationInfo info)
{
Console.WriteLine("Hello, CodeProject!");
object result = null;
return result;
}
public void AfterInvoke(InvocationInfo info, object returnValue)
{
Console.WriteLine("AfterGreet() called");
}
}
The first thing that you might notice here is that the interceptor needs to have a reference to an actual instance of a greeter object. That's because LinFu
's dynamic proxies don't actually have a behavior (or an intrinsic state) of their own. Every proxy generated by LinFu
dynamically overrides all of its parent's virtual methods. Each one of its respective overridden method implementations delegates each method call to the attached IInterceptor
object. In many respects, each proxy is like an empty shell. Without an attached interceptor, a proxy simply throws a NotImplementedException
.
A Manually Written Proxy
If I were to write the proxy by hand, it would look something like this:
public class GreeterProxy : Greeter, IProxy
{
private IInterceptor _interceptor;
public override void Greet()
{
if(_interceptor == null)
throw new NotImplementedException();
InvocationInfo info = new InvocationInfo();
_interceptor.Intercept(info);
}
public IInterceptor Interceptor
{
get
{
return _interceptor;
}
set
{
_interceptor = value;
}
}
}
As you can see here, LinFu
's dynamic proxies only redirect calls to an interceptor, despite whatever implementations each proxy might inherit from its original base class. When a proxy is called in place of an actual object, it constructs an InvocationInfo
object with all the necessary reflection details. This is so that the interceptor can either call the original implementation of that method or replace it with its own brand new implementation.
InvocationInfo Objects
The InvocationInfo
class, in turn, is defined as:
public class InvocationInfo
{
public object Target
{
get
{
return _proxy;
}
}
public MethodInfo TargetMethod
{
get
{
return _targetMethod;
}
}
public StackTrace StackTrace
{
get
{
return _trace;
}
}
public MethodInfo CallingMethod
{
get
{
return (MethodInfo) _trace.GetFrame(0).GetMethod();
}
}
public Type[] TypeArguments
{
get
{
return _typeArgs;
}
}
public object[] Arguments
{
get
{
return _args;
}
}
}
Most of the properties in this class are fairly self-explanatory. The Target
property refers to the proxy instance that intercepted the method call, while the StackTrace
property refers to the state of the call stack when the proxy was called.
What seems to be missing here, however, is any reference to the actual object that will provide the implementation for this proxy (in this case, a Greeter
object). This is done by design. As far as the LinFu
library is concerned, a proxy's sole task is to delegate its implementation to an IInterceptor
object which may (or may not) have an implementation of the real object as its implementation (i.e. the actual Greeter
object). Everything else (from the proxy's standpoint) is irrelevant.
Note: I separated the proxy instance from the proxy implementation (and thus, the real object) to make it easier to manage multiple proxies at once. In theory, a handful of these proxies could be pooled together and reused to save memory, but such a task is way beyond the scope of this article. I'll leave it to the readers to come up with a scheme to make that work.
Putting It All Together
Now that there is a GreetInterceptor
class, the only things left to do are to instantiate the proxy and attach it to the greeter
:
ProxyFactory factory = new ProxyFactory();
Greeter actualGreeter = new actualGreeter();
GreetInterceptor interceptor = new GreetInterceptor(actualGreeter);
Greeter greeter = factory.CreateProxy<Greeter>(interceptor);
Once the greeter
proxy object is instantiated and initialized with the interceptor, the only thing left to do is to run it:
greeter.Greet();
After the Greet()
method is called, the proxy will redirect the call back to the GreetInterceptor
instance, which will provide the replacement implementation for the Greet()
method. Aside from the proxy instantiation itself, this process makes intercepting method calls relatively transparent. What if, however, you need to replace the interceptor?
The IProxy Interface
As it turns out, every proxy generated by LinFu
implements the IProxy
interface. Since the IProxy
interface has an Interceptor
property, replacing an existing interceptor
is as easy as doing the following:
IInterceptor otherInterceptor = new SomeOtherInterceptor();
IProxy proxy = (IProxy)greeter;
proxy.Interceptor = otherInterceptor;
greeter.Greet();
Points of Interest
One thing about LinFu
's DynamicProxy
that's always fascinated me is its raw speed. On my 1.8GHz Dual-core laptop, it takes only a few milliseconds to generate a single proxy. For the sake of reference, I've done a simple benchmark on LinFu
's Dynamic Proxy versus CastleProject's DP2.
Benchmark Setup
This benchmark was run against both LinFu
and Castle DP2 libraries with proxy type caching turned off. This was to prevent any of the results from being skewed due to cache hits from either library. For Castle's DynamicProxy2, I had to modify BaseProxyGenerator.cs, line 160, to disable caching:
protected void AddToCache(CacheKey key, Type type)
{
}
For LinFu
, I disabled the proxy cache from being used by setting its reference to null
in Program.cs, line 104, in the benchmarking code:
…
ProxyFactory factory = new ProxyFactory();
factory.Cache = null;
…
Benchmark Results
This test simulates a worst-case scenario where each proxy generator (or factory) effectively has to generate up to one thousand unique proxy types in succession. As the results of this benchmark show, both of these libraries scale quite well when generating up to one hundred unique proxy types. However, Castle's performance significantly slows down once the benchmark passes the one hundred type threshold. In fact, as it approaches the point where it has to generate a thousand unique types, it runs five times slower than LinFu
's implementation. Other than that, I think the benchmark speaks for itself.
Since type caching is enabled by default in both libraries, however, multiple calls to generate the same proxy type will be cached and those calls (in practice) will only incur a minimal amount of overhead. Nonetheless, this benchmark shows the speed differences between the two libraries and, as these numbers show, LinFu
's DynamicProxy
is much faster than its Castle counterpart.
Note: If you should be inclined to perform benchmarks of your own, I've included the benchmarking code as part of the source code, as well as the Excel 2007 spreadsheet that I used to generate that chart for the benchmarks. I've also included a copy of the modified Castle.DynamicProxy2.dll with its caching disabled, just in case someone else on CodeProject would be interested in adding even more benchmarks.
Limitations
There are a few things that LinFu
's Dynamic Proxy generator cannot do. These are:
It cannot inherit from sealed types.
By itself, LFDP cannot override a sealed type. However, once I get to discussing LinFu.Reflection
, I'll show you how to get around this limitation.
It cannot override non-virtual members.
This one is pretty self-explanatory. Lately, I've been playing around with using the Mono.Cecil
library to make non-virtual methods virtual, but so far, I haven't come up with anything robust enough to include in LinFu
. I'll update this article once I come up with something reliable.
Special Thanks
Thanks to Jeff Brown and Julien Dagorn, LinFu.DynamicProxy
now supports overriding methods with ref
and out
parameters. Thanks for the input, guys!
License
The entire LinFu
Framework is licensed under the terms of the LGPL license, meaning that you are free to use the library DLL in your commercial applications without royalties, but if you make any modifications to its source code, then you must publish the source code so that everyone else can use it.
Coming Up in the Next Article
LinFu
's DynamicProxy
is only a rudimentary part of what the overall LinFu
Framework has to offer. In the next article, I'll show you how you can use the features of C# 3.0 along with LinFu
to dynamically generate interface implementations at runtime. I'll give you an example. Suppose that in my domain model, I have the following interface definitions defined:
public interface IPerson
{
string Name
{
get;
}
int Age
{
get;
}
}
public interface IDogOwner
{
int NumberOfDogsOwned
{
get;
}
}
Using LinFu
's DynamicObject
and the new features of C# 3.0 (namely, anonymous types), I can implement these interfaces at runtime using only the following code:
DynamicObject dynamicObject = new DynamicObject(new object())
dynamicObject.MixWith(new { Name="Me", Age=18 });
dynamicObject.MixWith(new { NumberOfDogsOwned=1 });
IPerson person = dynamicObject.CreateDuck<IPerson>();
string name = person.Name;
int age = person.Age;
IDogOwner dogOwner = dynamicObject.CreateDuck<IDogOwner>();
int dogsOwned = dogOwner.NumberOfDogsOwned;
For now, I'll let you digest that last block of code in your mind for awhile. Suffice to say, LinFu
allows developers to use dynamic language features from within the comforts of their own statically typed languages. Meanwhile, I'll be off writing the next article. Stay tuned!
History
- 15 October, 2007 -- Original version posted
- 26 October, 2007 -- Article and downloads updated
- 5 November, 2007 -- All downloads updated
- 12 November, 2007 -- Source and binary downloads updated