开发者

DLR LambdaExpressions and the System.Runtime.CompilerServices.Closure object

I'm working on a small programming language for the Microsoft DLR, and having a bit of a problem invoking my anonymous methods. Specifically, the code:

Delegate CompiledBody = Expression.Lambda(rt.Parser.ParseSingle(Body), parms).Compile();

So, parms is an array containing a single ParameterExpression, and the first argument contains the appropriate Expressions to define the anonymous function. When I try to invoke my Delegate using an Expression.Call on C开发者_JS百科ompiledBody.Method (a MethodInfo), I receive the error:

Unhandled Exception: System.ArgumentException: Expression of type 'System.Object' 
cannot be used for parameter of type 'System.Runtime.CompilerServices.Closure' 
of method 'Shiro.Runtime.ShiroAtom lambda_method(System.Runtime.CompilerServices
.Closure, Shiro.Runtime.ShiroAtom)'

Now, somewhere along the way my one-argument method gained a second argument, of type System.Runtime.CompilerServices.Closure (the second one, of type ShiroAtom, is my parameter). This makes sense, except that (a) I don't really care if the method in this context is in a Closure scope and (b) I can't seem to create even an empty Closure scope to pass in this parameter.

I'd appreciate any help! Thanks in advance.

EDIT: Some additional information based on the awesome reply below:

Where this code occurs is deep in the bowels of my Parser. I have a stream of tokens (actually, Atoms) which get translated into an AST. This particular bit is the function call parse routine. It created a CompiledBody, then tries to invoke it using something like:

return Expression.Call(CompiledBody.Method, Expression.Constant("argument"));

The resulting Lambda represents a function. Based on my architecture there are only a few places I can call DynamicInvoke or just calling the Compiled Delegate, and this isn't one of them. I wish I could provide a more substantial example but this situation occurs in the midst of a hand-coded parser, and it would take way too much code to really communicate why the situation is this way, but I really need a way to call the compiled Lambda via Expression.Call, as shown above.

The crux of the problem is that my Compiled Lambda requires 1 additional parameter to the ones I specify, a CompilerServices.Closure, and I don't know how to make one.


It would be helpful if you could share the body that you're compiling as that would contain the actual closure and how you're invoking it. My guess is that you are attempting to invoke the resulting delegate "by hand" somehow instead of holding onto something of the delegate object and simply generating an Invoke expression. If you want to use the DLR closures this is how it should look:

using System;
using System.Linq.Expressions;

class Program {
    static void Main(string[] args) {
        var outerParam = Expression.Parameter(typeof(int), "outerParam");

        var lambda =
            Expression.Lambda<Func<int, Action>>(
                Expression.Lambda<Action>(
                    Expression.Call(
                        typeof(Console).GetMethod("WriteLine", new Type[] { typeof(object) }),
                        Expression.Convert(outerParam, typeof(object))
                    )
                ),
                outerParam
            ).Compile();

        var actionParam = Expression.Parameter(typeof(Action), "action");
        var lambdaInvoker =
            Expression.Lambda<Action<Action>>(
                Expression.Invoke(actionParam),
                actionParam
            ).Compile();

        lambdaInvoker(lambda(100));
        lambdaInvoker(lambda(200));
        Console.ReadLine();
    }
}

That creates 3 lambdas: The 1st one contains a 2nd inner lambda which closes over a parameter. The type of the resulting closure delegate is the type specified when creating the lambda expression even though there's an extra hidden parameter there. The 3rd lambda shows how you can invoke this from another lambda - that is via a delegate invocation. Finally we chain the delegates together to show how it works.

Also one thing to be aware of us that DLR closures don't actually perform that great right now due to a limitation in the CLR. Creating the closure is actually a pretty slow process because it needs to go through reflection instead being able to create the delegate directly. If you're concerned about performance of delegate you'll want to track the variables and flow closed over values in via your own data structure (this is what both IronRuby and IronPython do).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜