Dynamic lambda expression with dynamic parameter

17 .net c# lambda dynamic

Given this class

public class Foo
{
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

This method (in some other class)...

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();
}
Run Code Online (Sandbox Code Playgroud)

Will take the right hand side of a lambda expression and give me back a delegate. So if it is called like this:

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);
Run Code Online (Sandbox Code Playgroud)

Then sub will have the value "Ham".

All well and good, however, I would like to make Foo subclass DynamicObject (so that I can implement TryGetMember to dynamically work out property values), so I want to take the expression and get the equivalent of this

Func<dynamic, dynamic> fn = foo => foo.Name.Substring(0,3);
Run Code Online (Sandbox Code Playgroud)

I've tried Expression.Dynamic using a custom CallSiteBinder, but that fails with No property or field Bar exists in type Object (when I try to access foo.Bar dynamically). I'm assuming that is because the call to get foo.Bar needs to be dynamically dispatched (using Expression.Dynamic), but that isn't going to work for me because a key aim is that a user can enter a simple expression and have it executed. Is it possible?

Dan*_*son 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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

动态对象

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}");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用案例:

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

当涉及到泛型方法时,这DynamicExpressionParser.ParseLambda也有点痛苦,所以我必须创建特定于类型的访问器,这不是最好的,但它有效。