Introduction
In this installment of the series, I'll show you how you can use LinFu.DynamicObject
to add dynamic language features to your code. I'll also discuss how LinFu.DynamicObject
does this behind the scenes and briefly touch upon how you can use it in conjunction with the new language features coming up in C# 3.0. Note: If you're wondering what the entire LinFu
Framework is about, click here.
Background
Since the version 1.0 release of the .NET Framework, many developers have been clamoring for features such as multiple inheritance and mixins. Unfortunately, due to the complexity of implementing multiple inheritance, mixins and the trouble those features entail, Microsoft left those features out of the .NET Framework.
Until recently, these feature requests have been largely ignored. However, thanks to upcoming dynamic languages like IronPython and IronRuby, Microsoft is finally starting to provide those language features that everyone else has been asking for. However, in order to use those features in your application, you have to switch your codebase to a new programming language. That might not be a feasible option if one has deadlines to meet and milestones to reach.
This scenario effectively leaves us developers with two options: One can either find a workaround for the statically typed, single-inheritance limitations imposed by C#, VB.NET and the CLR, or one can take Reflection.Emit
into their own hands and implement those features themselves. Most sane developers would have taken the first option. Thankfully, I am not a sane person when it comes to coding and thus, LinFu.DynamicObject
was born.
What You Need to Know
This article assumes that you know enough about dynamic language features such as mixins, multiple dispatch and the like. It also assumes that you understand enough about dynamic proxies to make use of the library.
Features and Usage
One of the most notable features about LinFu.DynamicObject
and the rest of the LinFu
library is that it is language-independent. Although the examples shown here are done in C#, anyone can easily use it in the same way in other languages, such as VB.NET. Aside from whichever programming language you wish to use, LinFu.DynamicObject
supports the following features:
Late Binding
Unlike typical method calls made by an application, LinFu.DynamicObject
doesn't know which method you will be using until the application is running. What LinFu.DynamicObject
does is actually determine which method you'll be using just by looking at the name of the method that you're calling, and the runtime arguments that are being passed to that method.
Here's an example. Suppose that I had an instance of a System.IO.StringWriter
class, which has multiple overloads of the WriteLine()
method:
StringWriter writer = new StringWriter();
DynamicObject dynamic = new DynamicObject(writer);
dynamic.Methods["WriteLine"]("Hello, World!");
dynamic.Methods["WriteLine"](false);
No matter what the method signature, LinFu.DynamicObject
makes it easy to perform late-bound calls to objects at runtime.
Multiple Dispatch
As I mentioned earlier, LinFu.DynamicObject
can match any method signature with any arbitrary number of arguments. Using this feature, I can do things that would otherwise be difficult (or impossible) to implement just by using the native features of a statically typed language alone. For example, suppose that I had a class named CollisionManager
that managed a bunch of shapes on the screen and that I wanted it to perform a certain set of actions when a certain set of shapes Collide()
:
public class CollisionManager
{
public void Collide(Circle circle, Square square, Triangle triangle)
{
Console.WriteLine("Overload #1 Called");
}
public void Collide(Square square, Circle circle, Triangle triangle)
{
Console.WriteLine("Overload #2 Called");
}
public void Collide(Triangle triangle, Square square, Circle circle)
{
Console.WriteLine("Overload #3 Called");
}
public void Collide(Triangle triangle, Circle circle)
{
Console.WriteLine("Overload #4 Called");
}
}
A Collision with Insanity
Now, suppose that I wanted to be able to call any one of these overloads, depending on both the order and type of each parameter, using only a single method call. Needless to say, doing something like this in a statically typed language is an outright nightmare. Fortunately, with LinFu.DynamicObject
, you no longer have to do this by hand. Calling those overloaded methods is just as simple as:
DynamicObject dynamic = new DynamicObject(new CollisionManager());
object[] list1 = new object[]{new Circle(), new Square(), new Triangle()};
object[] list2 = new object[]{new Square(), new Circle(), new Triangle()};
object[] list3 = new object[]{new Triangle(), new Square(), new Circle()};
object[] list4 = new object[]{new Circle(), new Triangle()};
dynamic.Methods["Collide"](list1);
dynamic.Methods["Collide"](list2);
dynamic.Methods["Collide"](list3);
dynamic.Methods["Collide"](list4);
As you can see from the example above, LinFu.DynamicObject
makes it easy to call the appropriate Collide()
method in spite of the number of overloads that might exist for that particular method. It can easily distinguish between the different method signatures. It does all of the boilerplate work for the developer, allowing you to focus on the more important tasks at hand.
Dynamic Methods
DynamicObject
also allows you to dynamically add methods to it at runtime by using the following methods:
public void AddMethod(string methodName, MulticastDelegate body);
public void AddMethod(string methodName, CustomDelegate body,
Type returnType, params Type[] parameters);
The first overload allows you to add a method using an existing delegate type (such as a delegate type that exists at compile time), while the second overload allows you to define a method with a particular signature and method body. I'll go over each example below:
Using an Existing Delegate Type
public delegate int MathOperation(int a, int b);
public class Program
{
public static void Main()
{
MathOperation body = delegate(int a, int b) { return a + b; };
DynamicObject dynamic = new DynamicObject();
dynamic.AddMethod("Add", body);
int result = (int)dynamic.Methods["Add"](1, 1);
}
}
In this example, I took an anonymous delegate of the type MathOperation
and gave it a method body. Using that body, I then created a method named Add
on DynamicObject
. Once the method was added, the only thing left to do was invoke it, giving 2
as the result. Using an existing delegate type can be handy if you already have an instance of a particular delegate in memory (such as an anonymous delegate) and you want to make it a part of DynamicObject
. The only problem with this approach is that it only allows you to add methods based on delegate types that exist at compile time. This can prevent a developer from generating methods at runtime. That is where the second overload can be used:
Using the CustomDelegate Type
public class Program
{
public static void Main()
{
CustomDelegate body = delegate(object[] args)
{
int a = (int)args[0];
int b = (int)args[1];
return a + b;
};
DynamicObject dynamic = new DynamicObject();
Type[] parameters = new Type[] {typeof (int), typeof (int)};
Type returnType = typeof (int);
dynamic.AddMethod("Add", body, returnType, parameters);
int result = (int)dynamic.Methods["Add"](1, 1);
}
}
Using the CustomDelegate
type allows me to define the body of the method without tying the method signature to any specific parameter types. In this example, I extracted the first two arguments from the args
array defined in the body
of the CustomDelegate
instance. Just as I did in the previous example, I then simply added the two numbers together and returned the result. The difference in this example was that I actually had to specify both the method return type and the method parameter types when I used the CustomDelegate
type as the method body.
The Choice is Yours
Other than those differences that I just mentioned, the two overloads work the same way. It's really up to you to decide whether you prefer the flexibility of CustomDelegate
or to use the signature of your own predefined delegate. In my opinion, the second choice would be the better option, since it is more dynamic and thus easier to maintain.
Duck Typing
Another one of LinFu.DynamicObject
's strengths is that it can make itself look and act like nearly any interface or non-sealed class. For example, suppose that I have the following interface defined:
public interface IMath
{
int Add(int a, int b);
}
Walking Like a Duck
Drawing on the examples from the previous section, I can take the same DynamicObject
and make it look and act like IMath
:
IMath math = null;
int result = 0;
if(dynamic.LooksLike<IMath>())
{
math = dynamic.CreateDuck<IMath>();
result = math.Add(1, 1);
}
Every time the CreateDuck()
method is called, DynamicObject
generates a proxy that implements the given class or interface (e.g. IMath
). That proxy, in turn, forwards all of its calls back to DynamicObject
to handle the actual method implementation. So, every time the IMath.Add()
method is invoked by the client, the proxy is calling DynamicObject
directly using the following method call:
return dynamic.Methods["Add"](1,1);
A Duck or Not a Duck?
In addition to acting like an IMath
instance, DynamicObject
can also determine whether or not it has a sufficient number of compatible methods and properties to implement that interface using the LooksLike()
method. This is useful if you want to make sure that DynamicObject
adheres to a specific interface type.
Mixins
LinFu.DynamicObject
also supports "mixing" (or combining) itself with other object instances to make it appear as if all of the mixed items form a cohesive class at runtime. In general, it supports three types of mixins:
Standard Object References
A DynamicObject
instance can mix itself with another object reference (that is, a plain old System.Object
-derived class), take all of the methods and properties of that class and make it a part of that DynamicObject
instance itself. For example, suppose that I wanted to implement an interface named IPerson
:
public interface IPerson
{
string Name { get; }
int Age { get; }
}
...and suppose that I wanted to implement that interface using instances of two hypothetical mixins named Nameable
and HasAge
:
public class Nameable
{
private string _name;
public Nameable(string name)
{
_name = name;
}
public string Name
{
get { return _name; }
}
}
public class HasAge
{
private int _age;
public HasAge(int age)
{
_age = age;
}
public int Age
{
get { return _age; }
}
}
As you can see, there's really nothing special about these two mixins. Creating an implementation of the IPerson
interface is as simple as:
DynamicObject dynamic = new DynamicObject();
IPerson person = null;
bool isPerson = dynamic.LooksLike<IPerson>();
dynamic.MixWith(new HasAge(18));
dynamic.MixWith(new Nameable("Me"));
isPerson = dynamic.LooksLike<IPerson>();
if (isPerson)
person = dynamic.CreateDuck<IPerson>();
string name = person.Name;
int age = person.Age;
The above example would work for simple cases where the mixins are simply property holders, but what if a mixin had more complicated operations that needed to have access to DynamicObject
?
Mixin-Aware Instances
For more advanced scenarios, a mixin itself might need to interact with the other mixins that are a part of the current DynamicObject
instance. If you need to have your mixins interact with DynamicObject
itself, all you need is to implement the following interface with your mixin:
public interface IMixinAware
{
DynamicObject Self { get; set; }
}
public class MyMixin : IMixinAware
{
private DynamicObject _self;
public void DoSomething()
{
DynamicObject dynamic = Self;
IMath math = dynamic.CreateDuck<IMath>();
math.Add(1, 1);
}
public DynamicObject Self
{
get { return _self; }
set { _self = value;}
}
}
public class MathMixin : IMath
{
public int Add(int a, int b)
{
return a + b;
}
}
The next thing that you have to do is call the MixWith()
method using your new mixin class:
DynamicObject dynamic = new DynamicObject();
dynamic.MixWith(new MathMixin());
dynamic.MixWith(new MyMixin());
Any mixin class that implements the IMixinAware
interface has the ability to access (and modify) the attached DynamicObject
at will and at any given time. In my opinion, the power that this feature gives is mind-boggling. For now, I think I'll leave it in the capable hands of the readers to figure out what to do with this. Anyway, let's move on to the next part: mixing DynamicObject
s with other DynamicObject
s.
Combining DynamicObjects
Combining two DynamicObject
s is as easy as:
public class GreeterMixin
{
public void Greet()
{
Console.WriteLine("Hello, World!");
}
}
public class OtherMixin
{
public void DoSomething()
{
Console.WriteLine("DoSomething() called");
}
}
class Program
{
static void Main(string[] args)
{
DynamicObject first = new DynamicObject(new GreeterMixin());
DynamicObject second = new DynamicObject(new OtherMixin());
DynamicObject combined = first + second;
combined.Methods["Greet"]();
combined.Methods["DoSomething"]();
}
}
When two DynamicObject
s are combined, it results in a new DynamicObject
that has all of the methods and mixins of both previous instances. This can cause a problem, however, if two dynamic objects have two of the same type of mixins. In the event of a mixin conflict, which mixin gets used?
Resolving Conflicts with Duplicate Mixins
There's no easy way to resolve this issue. In fact, this is probably one of the reasons why Microsoft left mixins and multiple inheritance out of the CLR in the first place. So, in the absence of a perfect solution, I decided to take the simplest one and apply it to LinFu.DynamicObject
: The first mixin in DynamicObject
is the first to execute. Here's an example:
public class GreeterMixin
{
private string _message;
public GreeterMixin(string message)
{
_message = message;
}
public void Greet()
{
Console.WriteLine(_message);
}
}
public static class Program
{
public static void Main()
{
GreeterMixin first = new GreeterMixin("Hello, World!");
GreeterMixin second = new GreeterMixin("Hello, CodeProject!");
DynamicObject dynamic = new DynamicObject();
dynamic.MixWith(first);
dynamic.MixWith(second);
dynamic.Methods["Greet"]();
}
}
In this scenario, the first GreeterMixin
will always be the first and only mixin to execute. This is because DynamicObject
will search all of its mixins and methods for the first method that has the same method name and a compatible method signature and it will execute just that one method. Every other method after the first method found will simply be ignored.
Points of Interest
Bypassing Sealed Methods and Types: "Duck Taping"
One problem that has dogged many developers when using various class libraries is when the given library author seals a type and prevents its methods from being overridden. In normal circumstances (that is, in statically typed languages), this is akin to hitting a brick wall. Fortunately, this isn't the case with LinFu.DynamicObject
. Generally, you can bypass a sealed type using the following steps:
Create (or Find) an Interface That Looks Like Your Target Type
The first thing that you need to do is figure out which methods or properties you will override in the target class. Then create an interface that is similar to the list of methods that you will be overriding. In this example, suppose that I wanted to override System.Data.SqlConnection
so that I got a notification every time I called IDbConnection.Open
()
. Since all connections inherit from System.Data.IDbConnection
(and, more importantly, they all look like IDbConnection
), I can use that interface as the type I will be using for duck typing.
Wrap the Sealed Class Instance and Create the Duck
DynamicObject dynamic = new DynamicObject(new SqlConnection());
IDbConnection duck = dynamic.CreateDuck<IDbConnection>();
Override the Duck
Next, we need to create an interceptor that wraps around the intended target method or methods. In this case, we want to wrap IDbConnection.Open()
:
public class CustomInterceptor : IInvokeWrapper
{
private object _target;
public class CustomInterceptor(object target)
{
_target = target;
}
public void BeforeInvoke(InvocationInfo info)
{
if (info.TargetMethod.Name != "Open")
return;
Console.WriteLine("Open Method Called!");
}
public object DoInvoke(InvocationInfo info)
{
object result = info.TargetMethod.Invoke(_target, info.Arguments);
return result;
}
public void AfterInvoke(InvocationInfo info, object returnValue)
{
}
}
Once the interceptor has been defined, the next thing to do is create a proxy for IDbConnection
. Then tie the duck and the CustomInterceptor
together into one instance:
ProxyFactory factory = new ProxyFactory();
IDbConnection unsealed =
factory.CreateProxy<IDbConnection>(new CustomInterceptor(duck));
unsealed.Open();
...and that's how you unseal a sealed type.
Interceptor by Design
For those of you who use LinFu
's DynamicProxy
, one thing that you might find interesting is that DynamicObject
s are interceptors themselves. This means that any DynamicObject
can act as an interceptor for any proxy created by LinFu.DynamicProxy
's ProxyFactory
class. For example, suppose that I already have an existing proxy in memory and I want to create a dynamic interceptor so that I can attach it to the proxy:
ProxyFactory factory = new ProxyFactory();
IMath math = factory.CreateProxy<IMath>();
DynamicObject interceptor = new DynamicObject();
IProxy proxy = math as IProxy;
proxy.Interceptor = interceptor;
...
This approach makes it easy to incrementally build an interceptor implementation as the application is running. The possibilities are endless.
Using DynamicObject with C# 3.0
Another realm of possibilities opens up once you combine the abilities of LinFu.DynamicObject
with the upcoming language features of C# 3.0. Some of these possibilities are:
Mixins Using Anonymous Types
Now that C# 3.0 has support for anonymous types, dynamically creating throwaway interface implementations is easy. Using an anonymous type, I can easily provide an implementation for IPerson
by using the following code:
DynamicObject dynamic = new DynamicObject();
dynamic.MixWith(new {Name="Me", Age=18});
IPerson person = dynamic.CreateDuck<IPerson>();
Console.WriteLine("Name = {0}", person.Name);
Console.WriteLine("Age = {0}", person.Age);
Shorter Anonymous Delegates with Lambda Expressions
While in some ways, being able to write shorter anonymous delegates using lambda expressions is no more than syntactic sugar, using lambda expressions with LinFu.DynamicObject
(in my opinion) makes the code a bit easier to read. For example, using the previous example with the MathOperation
type, I can rewrite it using lambda expressions so that it looks something like:
public delegate int MathOperation(int a, int b);
public class Program
{
public static void Main()
{
MathOperation body = (a, b)=> { return a + b; };
DynamicObject dynamic = new DynamicObject();
dynamic.AddMethod("Add", body);
int result = (int)dynamic.Methods["Add"](1, 1);
}
}
Saving Space
At first, saving yourself from typing a few characters doesn't seem to be a marginal gain in efficiency, but what if the IMath
class were defined as:
public interface IMath
{
int Add(int a, int b);
int Subtract(int a, int b);
int Multiply(int a, int b);
int Divide(int a, int b);
}
What was once one small declaration has turned itself into four and you have effectively increased the amount of items you have to type by 400%. What if you had to type even more than that? Suffice it to say, once you've gotten past ten repetitive anonymous delegate declarations, you'll be well past the point of tedium. For the sake of simplicity, however, let's stick to the four operations mentioned above.
The next thing that I have to do is redefine all of the operations performed by the IMath
class:
MathOperation add = (a, b) => { return a + b; }
MathOperation subtract = (a, b) => { return a – b; };
MathOperation multiply = (a, b)=> { return a * b; };
MathOperation divide = (a, b)=> { return a / b; };
Once again, in DynamicObject
, I have to add the new methods and implement the interface:
DynamicObject dynamic = new DynamicObject();
dynamic.AddMethod("Add", add);
dynamic.AddMethod("Subtract", subtract);
dynamic.AddMethod("Multiply", multiply);
dynamic.AddMethod("Divide", divide);
IMath math = dynamic.CreateDuck<IMath>();
Console.WriteLine(math.Add(1, 1));
Console.WriteLine(math.Subtract(1, 1));
Console.WriteLine(math.Multiply(1, 1));
Console.WriteLine(math.Divide(1, 1));
As you can see here, being able to use lambda expressions in place of full-length anonymous delegate declarations can save quite a lot of time and typing. As for the rest of the code above, well, if you've gone this far into the article, then everything I mentioned above is practically boilerplate. It's almost as if dynamically adding methods were nothing new, but I digress.
Parsing LINQ Expression Trees
With LINQ coming up on the horizon, LinFu.DynamicObject
naturally makes for a near-perfect expression tree visitor. Here's a simple (and hypothetical) example of a visitor using DynamicObject
:
public class ExampleVisitor
{
...
public void DoVisit(Expression expression)
{
DynamicObject dynamic = new DynamicObject(this);
dynamic.Methods["Visit"](expression);
}
public virtual void Visit(MethodCallExpression expression)
{
}
public virtual void Visit(BinaryExpression expression)
{
}
...
}
In this example, I wrapped ExampleVisitor
using the DynamicObject
class and I let DynamicObject
determine which overload of the Visit()
method will handle the current LINQ Expression. Once the client code calls DoVisit()
, DynamicObject
will walk the tree, leaving you to do something useful with the expression metadata.
LinFu.Reflection Features Still on the Drawing Board
The Wish List
Now that you have LinFu
in your hands, here is a list of things that I would love to implement, but frankly, I don't have enough time or expertise to effectively come up with a solution to. If you have any personal projects that are similar to what I'm doing here, it would certainly be a pleasure for me to compare notes with you on these subjects. Anyway, here's the list:
Anonymous Interfaces
One of the problems in using LinFu.DynamicObject
is that, aside from using the LooksLike()
method, there is currently no way to tell which methods and properties DynamicObject
implements. It would be nice to be able to have DynamicObject
dynamically generate some type information that would allow it to describe its current internal state. This is where the concept of anonymous interfaces comes in. I can have each DynamicObject
generate a nameless type that describes its current interface. I can use these dynamically generated anonymous interfaces and compare them with each other and test them for equality. Until I can figure out how to do this, it is nearly impossible to compare two dynamic objects and determine if they share the same methods and properties.
Differential Interfaces
Have you ever wanted to take two classes, put them side by side, and see which properties and methods they have in common? For example, let's say that I wanted to compare an ASP.NET button control with a standard Windows Forms button control. I want to be able to immediately determine which members these two classes have in common so that I can dynamically generate an interface to use for duck typing, employing those common members as part of the newly generated interface. The difference here is that I want this information dynamically generated at runtime and in memory, instead of having something that's scrawled on scraps of paper or a whiteboard that I cannot use.
Type Coercion Using TypeConverters
The general idea here is to modify DynamicObject
to be smart enough to figure out whether or not a given runtime argument is compatible with a method signature by checking to see if that argument has a value that is convertible to the target argument type. In other words, I want to make DynamicObject
smart enough to convert strings to enums and vice versa, as well as be able to convert integers to their numeric values and vice versa.
Invoking Late-bound Generic Methods with Open Type Parameters
LinFu.DynamicObject
works well with generic methods with closed (read: assigned) type parameters, but right now there's no way to invoke a method if the class has something like the following signature:
public class SomeClass
{
public void DoSomething<T>()
{
}
}
In its current state of development, LinFu.DynamicObject
cannot invoke the DoSomething<T>()
method because there is currently no way to tell DynamicObject
that I am looking for a method with an open generic type parameter and that I want to instantiate it using the type parameter that I'm assigning to it. This process is rather complicated and it will take me quite a while to figure out how to implement.
Coming Up in the Next Article
In Part III of this series, I'll show you how you can use LinFu.Delegates
to define closures with lambda arguments. I'll also show you how to use the EventBinder
class to handle any event, regardless of the delegate signature used by any particular event. Here's an example:
MathOperation add = delegate(int a, int b) { return a + b; };
Closure doMath = new Closure(add, new Closure
(add, new Closure(add, 12, 9), 11), Args.Lambda);
int result = (int) doMath.Invoke(20);
...and suppose I wanted to use EventBinder
to bind to a Windows Forms Button.Click
event:
Button button = new Button();
CustomDelegate handler = delegate { Console.WriteLine("Button Clicked!"); };
EventBinder.BindToEvent("Click", button, handler);
...and if I really wanted to get fancy, I could even use Closure
s with LinFu.DynamicObject
:
Closure lazyMathOperation = new Closure
(dynamic.Methods["Add"], 1, Args.Lambda);
int result = (int) lazyMathOperation.Invoke(5);
One Last Word Before the Next Article
Now that I'm effectively done discussing LinFu
's dynamic language extensions, my challenge to you as a fellow developer is to take this language's features and make something useful out of it. While you find something to do with it, I'll be finishing the rest of Part III. Stay tuned!
History
- 26 October, 2007 -- Original version posted
- 5 November, 2007 -- Article and downloads updated
- 12 November, 2007 -- Source and binary downloads updated