C# 如何从字符串值构建表达式树

C# 如何从字符串值构建表达式树,c#,entity-framework,linq,expression-trees,C#,Entity Framework,Linq,Expression Trees,我在其他地方问了一个特定的问题,但在没有回答和调查之后,我把问题归结为更一般的问题,但我仍在努力构建一个表达式树 我正在使用第三方库,它使用接口和扩展方法进行一些映射。这些映射被指定为表达式树,我要做的是从字符串值构建表达式树 扩展方法签名: public static T UpdateGraph<T>(this DbContext context, T entity, Expression<Func<IUpdateConfiguration<T>, obje

我在其他地方问了一个特定的问题,但在没有回答和调查之后,我把问题归结为更一般的问题,但我仍在努力构建一个表达式树

我正在使用第三方库,它使用接口和扩展方法进行一些映射。这些映射被指定为表达式树,我要做的是从字符串值构建表达式树

扩展方法签名:

public static T UpdateGraph<T>(this DbContext context, T entity, Expression<Func<IUpdateConfiguration<T>, object>> mapping = null, bool allowDelete = true) where T : class, new();
所以通常的显式用法是:

dbContext.UpdateGraph(person, mapping => mapping.OwnedEntity(p => p.House).OwnedEntity(p=> p.Car));
我需要做的是从属性名列表中建立映射

var props = {"Car","House"}

dbContext.UpdateGraph(person, buildExpressionFromStrings<Person>(props);

var props={“汽车”、“房子”}
UpdateGraph(person,buildExpressionFromStrings(props);
到目前为止,我有:


static Expression<Func<IUpdateConfiguration<t>, object>> buildExpressionFromStrings<t>(IEnumerable<string> props)
{
   foreach (var s in props)
   {
        var single = buildExpressionFromString(s);
        somehow add this to chaining overall expression

    }      
}

static Expression<Func<IUpdateConfiguration<t>, object>> buildExpressionFromString<t>(string prop)
            {
                var ownedChildParam = Expression.Parameter(typeof(t));

                var ownedChildExpression = Expression.PropertyOrField(ownedChildParam, prop);

                var ownedChildLam = Expression.Lambda(ownedChildExpression, ownedChildParam);

                // Up to here I think we've built the (o => o.Car) part of map => map.OwnedEntity(o => o.Car)
// So now we need to build the map=>map.OwnedEntity(ownedChildLam) part, by calling Expression.Call I believe, but here I'm getting confused.
            }

静态表达式BuildExpressionFromString(IEnumerable props)
{
foreach(道具中的变量s)
{
var single=buildExpressionFromString;
以某种方式将其添加到链接整体表达式中
}      
}
静态表达式buildExpressionFromString(字符串属性)
{
var ownedChildParam=表达式.参数(typeof(t));
var ownedChildExpression=Expression.PropertyOrField(ownedChildParam,prop);
var ownedChildLam=Expression.Lambda(ownedChildExpression,ownedChildParam);
//到目前为止,我认为我们已经构建了map=>map.OwnedEntity(o=>o.Car)的(o=>o.Car)部分
//因此,现在我们需要通过调用Expression.Call来构建map=>map.OwnedEntity(ownedChildLam)部分,我相信这一点,但这里我有点困惑。
}

实际上,真实世界的代码比这更复杂(需要处理递归和子属性/映射),但我想一旦我为一个级别构建了表达式,我就可以对它进行排序。我已经花了一天多的时间,试图对它进行排序…为了提供一些上下文,我使用实体框架和一些配置来定义聚合根。

我使用对象生成器来定义给定的道具。我使用基于字符串的表达式

没什么值得一提的。这里

mapping => mapping.OwnedEntity(p => p.House).OwnedEntity(p=> p.Car)
lambda表达式主体的部分不是lambda表达式,而是链式方法调用表达式,第一部分使用lambda expression参数,第二部分使用前一个结果

其次,扩展方法只是静态方法调用C#sugar,在表达式树中它们必须作为静态方法“调用”

所以,建立一个呼叫

public static IUpdateConfiguration<T> OwnedEntity<T, T2>(this IUpdateConfiguration<T> config, Expression<Func<T, T2>> expression);
publicstaticiupdateconfiguration-OwnedEntity(此IUpdateConfiguration配置,表达式);
可能是这样

static Expression BuildConfigurationCall<T>(Expression config, string propertyName)
{
    var parameter = Expression.Parameter(typeof(T), "it");
    var property = Expression.Property(parameter, propertyName);
    var selector = Expression.Lambda(property, parameter);
    return Expression.Call(
        typeof(UpdateConfigurationExtensions),
        nameof(UpdateConfigurationExtensions.OwnedEntity),
        new [] { typeof(T), property.Type },
        config,
        selector);
}
静态表达式BuildConfigurationCall(表达式配置,字符串属性名称)
{
var参数=表达式参数(类型(T),“it”);
var property=Expression.property(参数,propertyName);
var选择器=Expression.Lambda(属性、参数);
返回表达式。调用(
类型(更新配置扩展),
名称(UpdateConfiguration Extensions.OwnedEntity),
新[]{typeof(T),property.Type},
配置,
选择器);
}
所讨论的lambda表达式是:

static Expression<Func<IUpdateConfiguration<T>, object>> BuildConfigurationExpression<T>(IEnumerable<string> propertyNames)
{
    var parameter = Expression.Parameter(typeof(IUpdateConfiguration<T>), "config");
    var body = propertyNames.Aggregate((Expression)parameter,
        (config, propertyName) => BuildConfigurationCall<T>(config, propertyName));
    return Expression.Lambda<Func<IUpdateConfiguration<T>, object>>(body, parameter);
}
静态表达式BuildConfigurationExpression(IEnumerable propertyNames)
{
var参数=Expression.parameter(typeof(IUpdateConfiguration),“config”);
var body=propertyNames.Aggregate((表达式)参数,
(config,propertyName)=>BuildConfigurationCall(config,propertyName));
返回表达式.Lambda(主体,参数);
}

请仅在评论中要求澄清。如果问题需要详细信息,请将其标记为“需要详细信息或清晰”。
static Expression BuildConfigurationCall<T>(Expression config, string propertyName)
{
    var parameter = Expression.Parameter(typeof(T), "it");
    var property = Expression.Property(parameter, propertyName);
    var selector = Expression.Lambda(property, parameter);
    return Expression.Call(
        typeof(UpdateConfigurationExtensions),
        nameof(UpdateConfigurationExtensions.OwnedEntity),
        new [] { typeof(T), property.Type },
        config,
        selector);
}
static Expression<Func<IUpdateConfiguration<T>, object>> BuildConfigurationExpression<T>(IEnumerable<string> propertyNames)
{
    var parameter = Expression.Parameter(typeof(IUpdateConfiguration<T>), "config");
    var body = propertyNames.Aggregate((Expression)parameter,
        (config, propertyName) => BuildConfigurationCall<T>(config, propertyName));
    return Expression.Lambda<Func<IUpdateConfiguration<T>, object>>(body, parameter);
}