0

我正在尝试使用 Expression.Dynamic() 来构建赋值操作...我想使用它来选择性地为我的语言中的某些自定义类型实例提供值类型语义。我不能用“静态”(?)表达式来做到这一点,因为我不知道实际类型是什么(我需要 MetaObject 实例及其 LimitType ...因此是 Expression.Dynamic() )。

这对我不起作用...如果用于从我的 OperationBinder 子类构建 MetaObject,Expression.Assign() 什么也不做。

头。怦怦直跳。上。桌子。为了。小时。

只是想知道这是否是受支持的行为,或者我是否在吠叫错误的树?

谢谢...

4

3 回答 3

3

I think you basically have 2 options. In either one though you should be using a custom binder instead of a subclass of OperationBinder. This is because you're not performing a cross-language operation. Instead you're implementing a part of your language semantics but just want the good DLR stuff. You should sub class MetaObjectBinder to make this happen (MetaAction in older builds).

So your two choices then are to either have an Ast.Dynamic that returns the new value that you assign into a local or you pass the value as a ref argument. These should look like:

Ast.Assign(localVal, Ast.Dynamic(new AssignBinder(...), localVal, newVal);

or

delegate void AssignDelegate<TLocal, TValue>(CallSite site, TLocal loc, TValue val);
Type dlgType = typeof(AssignDelegate).MakeGenericType(new Type[] { localVal.Type, newVal.Type });
Ast.Dynamic(dlgType, new AssignBinder(...), localVal, newVal);

In your binder you'll override the Bind method which will give you the incoming MetaObject's. For the 1st one you'll just return the new value and the second one you'll just assign to the 1st MetaObject.

I haven't tried this but that's basically how it should work.

于 2009-01-07T03:53:38.657 回答
0

如果要创建赋值表达式,只需创建一个调用通用赋值例程的表达式。下面的类提供了一个很好的扩展方法,它将任何字段访问表达式转换为字段赋值表达式:

using System;
using System.Linq.Expressions;
using System.Reflection;

namespace Ethica.Expressions
{
    public static class ExpressionExtenstions
    {
        private class AssignmentHelper<T>
        {
            private static void SetValue(ref T target, T value)
            {
                target = value;
            }

            internal static MethodInfo MethodInfoSetValue =
                typeof(AssignmentHelper<T>).GetMethod("SetValue", BindingFlags.NonPublic | BindingFlags.Static);
        }


        public static Expression<Action<TInstance, TProp>> ToFieldAssignExpression<TInstance, TProp>
            (
                this Expression<Func<TInstance, TProp>> fieldGetter
            )
        {
            if (fieldGetter == null)
                throw new ArgumentNullException("fieldGetter");

            if(fieldGetter.Parameters.Count != 1 || !(fieldGetter.Body is MemberExpression))
                throw new ArgumentException ("Input expression must be a single parameter field getter, e.g. g => g._fieldToSet  or function(g) g._fieldToSet");

            ParameterExpression[] parms = new ParameterExpression[] {
                                        fieldGetter.Parameters[0], 
                                        Expression.Parameter(typeof(TProp), "value")};

            Expression body = Expression.Call(AssignmentHelper<TProp>.MethodInfoSetValue,
                                              new Expression[] { fieldGetter.Body, parms[1] });

            return Expression.Lambda<Action<TInstance, TProp>>(body, parms);
        }


        public static Action<TInstance, TProp> ToFieldAssignment<TInstance, TProp>
            (
                this Expression<Func<TInstance, TProp>> fieldGetter
            )
        {
            return fieldGetter.ToFieldAssignExpression().Compile();
        }
    }
}
于 2009-11-07T12:04:24.053 回答
0

你能澄清一下确切的情况吗?我非常熟悉Expression,并且非常熟悉将它与 DLR 树 / 4.0 一起使用,但我不能 100% 确定您要做什么。另请注意,这种类型的使用无论如何都有一些限制(无论是 C# 还是原始树)。

于 2009-01-06T07:54:55.160 回答