表达式.动态和运算符.分配?

发布于 2024-07-11 11:18:11 字数 361 浏览 11 评论 0 原文

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

这对我不起作用...如果用于从我的 OperationBinder 子类构建 MetaObject,Expression.Assign() 不会执行任何操作。

头。 重击。 在。 桌子。 为了。 小时。

只是想知道这是否是受支持的行为,或者我是否找错了树?

谢谢...

I'm trying to use Expression.Dynamic() to build an assignment operation... I want to use this to selectively offer value type semantics to certain custom type instances in my language. I can't do this with a "static" (?) Expression because I don't know what the actual type is (I need the MetaObject instance and its LimitType... hence Expression.Dynamic() ).

This isn't working for me... Expression.Assign() does nothing if used to build a MetaObject from my OperationBinder subclass.

Head. Pounding. On. Desk. For. Hours.

Just wondering if this is a supported behavior, or if I'm barking up the wrong tree?

Thanks...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

神也荒唐 2024-07-18 11:18:12

我认为你基本上有两个选择。 在任何一种情况下,您都应该使用自定义绑定器而不是 OperationBinder 的子类。 这是因为您没有执行跨语言操作。 相反,您正在实现语言语义的一部分,但只想要好的 DLR 内容。 您应该将 MetaObjectBinder 子类化以实现此目的(旧版本中的 MetaAction)。

因此,您的两个选择是要么使用 Ast.Dynamic 返回您分配给本地的新值,要么将该值作为 ref 参数传递。 它们应该如下所示:

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);

在您的活页夹中,您将重写 Bind 方法,该方法将为您提供传入的 MetaObject。 对于第一个,您只需返回新值,第二个您只需分配给第一个元对象。

我还没有尝试过,但这基本上就是它应该如何工作。

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.

岁吢 2024-07-18 11:18:12

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

Can you clarify the exact scenario? I'm very familiar with Expression, and passably familiar with using it with DLR trees / 4.0, but I'm not 100% sure what you're trying to do. Note also that there are some limitations anyway with this type of usage (whether it is C# or raw trees).

水溶 2024-07-18 11:18:12

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

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();
        }
    }
}

If you want to create an assignment expression, simply create an expression that invokes a generic assignment routine. The class below provides a nice extension method that will convert any field access expression into a field assignment expression:

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();
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文