Coercing Types and Unloading Assemblies

by Justin Chase 3. March 2010 09:09

I was doing a little experimentation recently related to building dynamic assemblies in .NET. One thing I found interesting was that if you create an instance of a dynamic Type then use the “dynamic” keyword to consume it, your dynamic assembly will never be unloaded.

That sort of defeats the purpose if you ask me. I was back to using reflection to call my dynamic objects. Not fun.

So I whipped up a quick dynamic coercion routine. Basically what it does is takes any instance and any interface and builds a wrapper object that implements the interface and calls a matching method on the instance. The instance does not need to implement the interface or even know about it. The coercion method will give the appearance of casting the instance into a interface it doesn’t really implement.

var instance = CreateDynamicAdder();
var adder = instance.Dynamic().Coerce<IAdder>();

Dynamic() is an extension point for type System.Object. Coerce is a extension method:

public static T Coerce<T>(this IDynamicExtensionPoint extensionPoint)
{
    if (!typeof(T).IsInterface)
        throw new ArgumentException("Type T must be an interface.");

    if (extensionPoint == null)
        throw new ArgumentNullException("extensionPoint");

    var assemblyBuilder = Dynamic.CreateDynamicAssembly();
    var wrapperType = BuildWrapperType(
        assemblyBuilder, 
        typeof(T), 
        extensionPoint.Instance.GetType());
    return (T)Activator.CreateInstance(wrapperType, extensionPoint.Instance);
}

So in the first code snippet I get an object that has a method I want to call that I know looks like this:

int Add(int x, int y)

I don’t know the exact Type and I don’t have any interfaces I can cast it into, but I know that this method is there, possibly through documentation, convention or debugging. The Coercion routine will allow me to call dynamic objects with an illusion of strong typing.

So I create an interface that matches the signature I am expecting.

public interface IAdder
{
    int Add(int x, int y);
}

And coerce the instance into this interface. What’s interesting is that when I do it this way, both the dynamic assembly creating the adder as well as the dynamic assembly creating the wrapper are unloaded when I drop references to them.

static void Main(string[] args)
{
    var numberOfAssemblies = AppDomain.CurrentDomain.GetAssemblies().Count();
    Console.WriteLine("Starting assembly count: " + numberOfAssemblies);

    var instance = CreateDynamicAdder();
    var adder = instance.Dynamic().Coerce<IAdder>();
    int z = adder.Add(7, 11);
    Console.WriteLine("Add result: " + z);
    instance = null;
    adder = null;

    numberOfAssemblies = AppDomain.CurrentDomain.GetAssemblies().Count();
    Console.WriteLine("Assembly count before collect: " + numberOfAssemblies);

    GC.Collect();
    GC.WaitForPendingFinalizers();

    numberOfAssemblies = AppDomain.CurrentDomain.GetAssemblies().Count();
    Console.WriteLine("Assembly count after collect: " + numberOfAssemblies);

    Console.ReadKey(true);
}

Here is the resulting screen shot, proving the dynamic assemblies are unloaded.

image

Download the full sample here:

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

.NET | C# | dynamic

Dynamically Compiled Lambdas vs. Pure Reflection

by Justin Chase 1. September 2009 05:45

I’ve spent a little time messing around with expression trees in .net 4 over the last couple of weeks and so I decided to put together a test comparing the performance of compiling a lambda expression on the fly vs. simply using basic reflection to invoke a method. You will probably see some of this in a patch to CSLA for Silverlight in the future, since it is currently calling pure reflection. Regular CSLA uses DynamicMethod and uses the ILGenerator to build a similar call to a method. And actually, looking in reflector, that is exactly what the LambdaExpression.Compile() method is doing also, its is simply easier to build up the code you are trying to compile using the Expression tree objects.

Setup

MethodInfo barMethod = typeof(Foo).GetMethod("Bar");
MethodInfo bazMethod = typeof(Foo).GetMethod("Baz");

int iterations = 100000;

Foo foo = new Foo();
object[] p1 = new object[] { 100, "blah" };
object[] p2 = new object[] { 100, "blah", Guid.Empty };
public class Foo
{
    public static int staticCount = 0;
    public int count = 0;

    public void Bar(int x, string y)
    {
        count++;
    }

    public static void Baz(int x, string y, Guid z)
    {
        Foo.staticCount++;
    }
}

Rather than doing all of this in the body of each test I wanted them both to have everything setup and even, in both cases we are getting the method to call with basic reflection. The Foo class is the class we will be running the test on and the fields are there simply to give the method body something to do so the compiler doesn’t optimize it out.

Invoke via Reflection

DateTime start = DateTime.Now;
for (int x = 0; x < iterations; x++)
{
    barMethod.Invoke(foo, p1);
    bazMethod.Invoke(null, p2);
}
DateTime end = DateTime.Now;
Console.WriteLine("Time with reflection: {0}.", (end - start).TotalMilliseconds);

Here we’re very simply calling the Invoke member of MethodInfo. The first method is a member method the second is static.

Invoke via Delegate

start = DateTime.Now;
Action<object, object[]> call = null;
Action<object, object[]> staticcall = null;
for (int x = 0; x < iterations; x++)
{
    if (call == null)
    {
        call = CreateCaller(barMethod);
        staticcall = CreateCaller(bazMethod);
    }

    call(foo, p1);
    staticcall(null, p2);
}
end = DateTime.Now;
Console.WriteLine("Time with dynamic lambdas: {0}.", (end - start).TotalMilliseconds);

Here we are building two delegates on the first iteration and calling it directly for subsequent iterations. I’m using Action<object, object[]> to allow me to very generically call any method. The more you know about the method you are trying to call the nicer the delegate signature could be (and probably a little faster) but this is also designed to be extremely general.

Also, note that I am using a null check for caching but in reality you would probably have something more complex like a dictionary. This would add a little extra overhead onto the execution time.

Create Caller via Expression Builder

Here is where the real interesting part takes place, here we are using the System.Linq.Expressions namespace to build a lambda expression dynamically based on the MethodInfo object passed in. The build lambda is compiled into a Delegate designed specifically to call that method. There are two types of methods built, one for member methods and one for static methods.

using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
private static Action<object, object[]> CreateCaller(MethodInfo method)
{
    int index = 0;
    var p1 = Expression.Parameter(typeof(object), "instance");
    var p2 = Expression.Parameter(typeof(object[]), "parameters");
    var parameters = from p in method.GetParameters()
                     select Expression.Convert(
                            Expression.ArrayAccess(
                            p2,
                            Expression.Constant(index++)),
                            p.ParameterType);

    Expression instanceCheck = null;
    Expression call = null;
    if (method.IsStatic)
    {
        instanceCheck = Expression.IfThen(
            Expression.NotEqual(
                p1,
                Expression.Constant(null)),
            Expression.Throw(
                Expression.New(
                    typeof(ArgumentException).GetConstructor(
                        new Type[] { 
                                typeof(string),
                                typeof(string) }),
                    Expression.Constant(
                        "Argument must be null for a static method call."),
                    Expression.Constant("instance"))));

        call = Expression.Call(
            method,
            parameters);
    }
    else
    {
        instanceCheck = Expression.IfThen(
            Expression.Equal(
                p1,
                Expression.Constant(null)),
            Expression.Throw(
                Expression.New(
                    typeof(ArgumentNullException).GetConstructor(
                        new Type[] { typeof(string) }),
                    Expression.Constant("instance"))));
        call = Expression.Call(
                    Expression.Convert(p1, method.DeclaringType),
                    method,
                    parameters);
    }

    var lambda = Expression.Lambda<Action<object, object[]>>(
            Expression.Block(
                instanceCheck,
                call),
            p1,
            p2);

    return lambda.Compile();
}

Results

When running the test application here are the results:

Time with reflection: 391.0391.
Time with dynamic lambdas: 15.0015.

Not surprisingly the dynamic lambdas vastly outperform standard reflection. But please note that this is in Milliseconds and is after 100,000 iterations. This sort of optimization is really only needed on areas where reflection is used heavily and frequently.

Action vs. Delegate

One of the interesting things I learned from this test was the difference between compiling a strongly typed delegate (such as System.Action) and a System.Delegate. Simply changing my lambda test code to this:

for (int x = 0; x < iterations; x++)
{
    if (call == null)
    {
        call = CreateCaller(barMethod);
        staticcall = CreateCaller(bazMethod);
    }

    call.DynamicInvoke(foo, p1);
    staticcall.DynamicInvoke(null, p2);
}

(notice the .DynamicInvoke() instead of direct invocation)

Changes the tests to yield the results:

Time with reflection: 393.0393.
Time with dynamic lambdas: 925.0925.

Which is dramatically worse than standard reflection! So the trick is that you really need to get a strongly typed delegate for it to be worthwhile at all to call. My above experiment attempts to solve the problem by using a general purpose Action<object, object[]> (which should probably be a Func<object, object, object[]> now that I think about it) and uses casting to resolve all of the problems with calling the method incorrectly but the fact of the matter is that the more you know about the method signature the better you will be able at optimizing it. For example, if you are able to know that there will never be any return values, that is a big optimization, or if you know a common base class for the instance method or if there will never be a static method then you can dramatically tweak this even further. The general solution is much more complex however.

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

dynamic | C# | .NET | CSLA

Dynamic Pipeline in MetaSharp

by Justin Chase 2. August 2009 03:14

I’ve been working on a prototype of a Dynamic Pipeline for MetaSharp using the new Linq Expressions in .NET 4. I’m pretty darn excited about it, here is what I have working so far:

[Test]
public void BinaryVariablesTest()
{
    var result = this.pipeline.Eval<int>("x * y", new { x = 3, y = 7 });
    Assert.AreEqual(21, result);
}

What I’m doing here is compiling the string as MetaSharp code then using a node visitor to generate the appropriate linq expressions. The trick here is the context parameter being passed in. This object contains all of the properties and methods allowed to be called from the expression, essentially it’s the “this” parameter. To get this to work you can use the handy dandy ConstantExpression. Here is how I’m doing it:

public class ReferenceExpressionVisitor 
    : TransformVisitor<linq.Expression, ReferenceExpression>
{
    protected override IEnumerable<linq.Expression> Visit(
        IEnumerable<linq.Expression> items, 
        ReferenceExpression visitedObject)
    {
        IDynamicContextService parameterService = 
            this.ServiceProvider.Locate<IDynamicContextService>();
    
        yield return linq.Expression.PropertyOrField(
            linq.Expression.Constant(parameterService.Context),
            visitedObject.Name);
    }
}

The constant allows us to call properties or fields on the context object directly. You should even be able to attach lambda expressions to fields so you can call those as well. I have to do some restructuring in order to enable everything like Method calls and whatnot but it should all be doable. Very sweet. Also the dynamic pipeline will have to have some type of caching provider, clearly you wouldn’t want to rebuild these expressions every single time you try to execute it. Optionally I could just give back a delegate instead of executing it directly, then let the caller do all the caching. That sounds easier and more flexible actually now that I think about it.

What’s cool about this though isn’t the fact that you can compile expressions dynamically (which is pretty cool but there are others out there already) but the fact that you will be able to dynamically compile DSLs… which reduce to dynamic expressions. Imagine this:

when truck is late:
  apply discount(.1);

when truck is early:
  apply bonus(.1);

when truck cost > $10,000:
  notify

You compile your DSL into MetaSharp nodes, transform it into Common language nodes then transform that into dynamic linq expressions. Very sweet! You might transform this into something like:

if(truck.late)
{
    context.discount(.1);
}
if(truck.early)
{
    context.bonus(.1);
}
if(truck.cost > 10000)
{
    context.notify();
}

Where you’d have a custom ShippingContext object with all of the methods and properties you wanted to expose in your DSL. This would be really handy for creating all sorts of systems that have the potential to have rapidly changing rules and also, potentially, enable business analysts to author their own rules.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

.NET | C# | DSL | dynamic | MetaSharp

Powered by BlogEngine.NET 1.4.5.0
Theme by Mads Kristensen

Justin Chase

sweetest hat ever

I am a software developer from St. Paul MN and I work for Microsoft on the Expression team. This blog is about various technical topics I find myself encountering here and there. In addition to loving WPF and Xaml and Expression studio in general I have a special interest in DSLs, programming languages and games.

RecentComments

Comment RSS

Calendar

<<  March 2010  >>
MoTuWeThFrSaSu
22232425262728
1234567
891011121314
15161718192021
22232425262728
2930311234

View posts in large calendar