c# - 字符串表达式到 c# 函数委托(delegate)

标签 c# lambda expression-trees func

我想将以下字符串转换为函数委托(delegate)。

[Id]-[Description]

C# 类:

public class Foo
{
    public string Id {get;set;}
    public string Description {get;set;}
}

结果函数委托(delegate):

Func<Foo, string> GetExpression = delegate()
{
    return x => string.Format("{0}-{1}", x.Id, x.Description);
};

我认为编译的 lambda 或表达式解析器是这里的一种方式,但不确定最好的方式。有什么意见吗?

最佳答案

可能是:构建 Linq 表达式然后编译它。编译表达式是一个普通的委托(delegate),没有性能缺陷。

如果参数类型 (Foo) 在编译时已知的实现示例:

class ParserCompiler
{
    private static (string format, IReadOnlyCollection<string> propertyNames) Parse(string text)
    {
        var regex = new Regex(@"(.*?)\[(.+?)\](.*)");

        var formatTemplate = new StringBuilder();
        var propertyNames = new List<string>();
        var restOfText = text;
        Match match;
        while ((match = regex.Match(restOfText)).Success)
        {
            formatTemplate.Append(match.Groups[1].Value);
            formatTemplate.Append("{");
            formatTemplate.Append(propertyNames.Count);
            formatTemplate.Append("}");

            propertyNames.Add(match.Groups[2].Value);

            restOfText = match.Groups[3].Value;
        }

        formatTemplate.Append(restOfText);

        return (formatTemplate.ToString(), propertyNames);
    }

    public static Func<T, string> GetExpression<T>(string text) //"[Id]-[Description]"
    {
        var parsed = Parse(text); //"{0}-{1}  Id, Description"

        var argumentExpression = Expression.Parameter(typeof(T));

        var properties = typeof(T)
            .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetField)
            .ToDictionary(keySelector: propInfo => propInfo.Name);

        var formatParamsArrayExpr = Expression.NewArrayInit(
            typeof(object), 
            parsed.propertyNames.Select(propName => Expression.Property(argumentExpression, properties[propName])));

        var formatStaticMethod = typeof(string).GetMethod("Format", BindingFlags.Static | BindingFlags.Public, null,new[] { typeof(string), typeof(object[]) }, null);
        var formatExpr = Expression.Call(
            formatStaticMethod,
            Expression.Constant(parsed.format, typeof(string)),
            formatParamsArrayExpr);

        var resultExpr = Expression.Lambda<Func<T, string>>(
            formatExpr,
            argumentExpression); // Expression<Func<Foo, string>> a = (Foo x) => string.Format("{0}-{1}", x.Id, x.Description);

        return resultExpr.Compile();
    }
}

和用法:

        var func = ParserCompiler.GetExpression<Foo>("[Id]-[Description]");
        var formattedString = func(new Foo {Id = "id1", Description = "desc1"});

关于c# - 字符串表达式到 c# 函数委托(delegate),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56184406/

相关文章:

c# - 使用 LinqToSQL 将参数传递到表达式规范

java - Guava future 中不明确的 lambda 重载

c# - 'MyClass' 类型的 ParameterExpression 不能用于 'System.Object' 类型的委托(delegate)参数

c# - 为什么我需要一个已加载程序集的 AssemblyResolve 处理程序?

c# - 无法使用connectionString连接到MySQL服务器

c# - 如何在不将转换器传递给 DeserializeObject 的情况下反序列化抽象项列表?

c# - If 语句或拆分中的多个条件

c# - 计算复杂的 lambda 表达式

c# - 已编译的 C# Lambda 表达式性能

c# - 未定义 MemberExpression 属性