动态lambda表达式与动态参数

时间:2018-02-20 15:17:06

标签: c# .net dynamic lambda

鉴于此课程

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 将具有值&#34; Ham&#34;。

一切都很好,但是,我想让Foo子类DynamicObject(这样我可以实现TryGetMember来动态计算属性值),所以我想采用表达式并得到相当于这个

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

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

1 个答案:

答案 0 :(得分:2)

我得到了这个,如果它能帮助你:

<强>编译器

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来创建对象,例如&#34; AddProperty&#34;对于每一处房产,但是heyho。

对于通用方法,DynamicExpressionParser.ParseLambda也有点痛苦,所以我必须创建特定于类型的访问器, 不是最好的,但是它正在工作。