【问题标题】:Dynamic lambda expression with dynamic parameter带有动态参数的动态 lambda 表达式
【发布时间】:2018-07-31 00:06:50
【问题描述】:

给定这个类

public class Foo
{
    public string Name { get; set; }
}

这个方法(在其他类中)...

private Func<Foo, string> Compile(string body)
{
    ParameterExpression prm = Expression.Parameter(typeof(Foo), "foo");
    LambdaExpression exp = DynamicExpressionParser.ParseLambda(new[] { prm }, typeof(string), body);
    return (Func<Foo, string>)exp.Compile();
}

将取 lambda 表达式的右侧并给我一个委托。所以如果它是这样调用的:

Foo f = new Foo { Name = "Hamilton Academicals" };
//foo => foo.Name.Substring(0,3)
Func<Foo, string> fn = Compile("foo.Name.Substring(0,3)");
string sub = fn(f);

那么 sub 的值将是“Ham”。

一切都很好,但是,我想让 Foo 成为 DynamicObject 的子类(这样我就可以实现 TryGetMember 来动态计算出属性值),所以我想采用表达式并获得等价的 this

Func<dynamic, dynamic> fn = foo => foo.Name.Substring(0,3);

我已经尝试使用自定义CallSiteBinder 使用Expression.Dynamic,但是由于类型Bar 中不存在Bar (当我尝试动态访问foo.Bar 时)而失败。我假设这是因为获取foo.Bar 的调用需要动态调度(使用Expression.Dynamic),但这对我不起作用,因为一个关键目标是用户可以输入一个简单的表达式和让它执行。有可能吗?

【问题讨论】:

  • 为此,我假设您需要另一个专门处理动态表达式的解析器。这个是行不通的。也许只是使用成熟的编译器(Roslyn)?预期的表达式有多复杂?
  • @Evk - 是的。在我发布后,我得出了同样的结论。表达式将很简单(一个衬里)。无法使用 Roslyn,因为生成的程序集不符合垃圾回收条件。
  • 您可以将生成的程序集加载到单独的应用程序域中并拆除它们。当然,这会影响性能,通常不是很好的解决方案,但总比没有好,具体取决于您对性能的要求。
  • True... 除非我想以 .NET Core 为目标
  • 好吧,那么我认为你很不走运,至少在他们在 .NET Core 中实现 dll 卸载之前(据我所知,这是即将推出的功能)。实现您自己的使用动态表达式的解析器可能并非易事。

标签: c# .net dynamic lambda


【解决方案1】:

如果能帮到你的话,我已经搞定了:

编译器

using System;
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;


namespace ConsoleApp4
{
    public class Compiler
    {
        public static Func<CustomDynamic, TResult> Compile<TResult>(string body)
        {
            ParameterExpression prm = Expression.Parameter(typeof(CustomDynamic), typeof(CustomDynamic).Name);
            LambdaExpression exp = DynamicExpressionParser.ParseLambda(new[] { prm }, typeof(TResult), body);
            return (Func<CustomDynamic, TResult>)exp.Compile();
        }
    }
}

动态对象

using System.Collections.Generic;
using System.Dynamic;

namespace ConsoleApp4
{
    public class CustomDynamic
    {
        ExpandoObject _values;
        public CustomDynamic()
        {
            _values = new ExpandoObject();
        }

        public void AddProperty(string propertyName, object propertyValue)
        {
            var expandoDict = _values as IDictionary<string, object>;
            if (expandoDict.ContainsKey(propertyName))
                expandoDict[propertyName] = propertyValue;
            else
                expandoDict.Add(propertyName, propertyValue);
        }

        public string GetString(string propertyName)
        {
            var expandoDict = _values as IDictionary<string, object>;
            if (expandoDict.ContainsKey(propertyName))
                return (string)expandoDict[propertyName];
            else
                throw new KeyNotFoundException($"dynamic object did not contain property {propertyName}");
        }
        public int GetInt(string propertyName)
        {
            var expandoDict = _values as IDictionary<string, object>;
            if (expandoDict.ContainsKey(propertyName))
                return (int)expandoDict[propertyName];
            else
                throw new KeyNotFoundException($"dynamic object did not contain property {propertyName}");
        }
    }
}

用例:

using System;

namespace ConsoleApp4
{
    class Program
    {
        static void Main(string[] args)
        {
            CustomDynamic f = new CustomDynamic();
            f.AddProperty("Name", "Hamiltonian Physics");

            Func<CustomDynamic, string> fn = Compiler.Compile<string>("CustomDynamic.GetString(\"Name\").SubString(0, 3)");

            string sub = fn(f);

            Console.WriteLine(sub);
            Console.ReadLine();
        }
    }
}

它只是利用了ExpandoObject 类。不幸的是,您需要通过它的 API 来创建对象,例如为每个属性创建“AddProperty”,但是嘿嘿。

DynamicExpressionParser.ParseLambda 对于泛型方法也有点麻烦,所以我不得不创建特定类型的访问器,这不是最好的,但它可以工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多