如何从字符串值构建表达式树
How to build expression tree from string values
我在其他地方问过一个具体问题,但在没有回应和一些调查之后,我将其归结为更通用的问题,但我仍在努力构建表达式树。
我正在使用第三方库,它使用接口和扩展方法进行一些映射。这些映射被指定为表达式树,我想要做的是从字符串值构建该表达式树。
扩展方法签名:
public static T UpdateGraph<T>(this DbContext context, T entity, Expression<Func<IUpdateConfiguration<T>, object>> mapping = null, bool allowDelete = true) where T : class, new();
接口IUpdateConfiguration只是一个标记接口,但有以下扩展方法:
public static class UpdateConfigurationExtensions
{
public static IUpdateConfiguration<T> OwnedCollection<T, T2>(this IUpdateConfiguration<T> config, Expression<Func<T, ICollection<T2>>> expression);
public static IUpdateConfiguration<T> OwnedCollection<T, T2>(this IUpdateConfiguration<T> config, Expression<Func<T, ICollection<T2>>> expression, Expression<Func<IUpdateConfiguration<T2>, object>> mapping);
public static IUpdateConfiguration<T> OwnedEntity<T, T2>(this IUpdateConfiguration<T> config, Expression<Func<T, T2>> expression);
public static IUpdateConfiguration<T> OwnedEntity<T, T2>(this IUpdateConfiguration<T> config, Expression<Func<T, T2>> expression, Expression<Func<IUpdateConfiguration<T2>, object>> mapping);
}
使用示例实体:
public class Person
{
public Car Car {get;set;}
public House House {get;set;}
}
所以正常的显式用法是:
dbContext.UpdateGraph(person, mapping => mapping.OwnedEntity(p => p.House).OwnedEntity(p=> p.Car));
我需要做的是从 属性 个名称列表中建立映射,
var props = {"Car","House"}
dbContext.UpdateGraph(person, buildExpressionFromStrings<Person>(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.
}
实际上,真实世界的代码比这更复杂(需要处理递归和子 properties/mappings),但我认为一旦我为一个级别构建了表达式,我就可以对其进行排序.一天多来我一直在努力整理头发,试图对此进行排序...为了提供一些背景信息,我正在使用 entity framework 和一些配置来定义聚合根。
我将 dynamic object creating with given props. And I use DynamicQueryable 的对象生成器用于基于字符串的表达式。
没什么好说的。这里
mapping => mapping.OwnedEntity(p => p.House).OwnedEntity(p=> p.Car)
lambda 表达式 body 的部分不是 lambda 表达式,而只是链式方法调用表达式,第一个使用 lambda 表达式参数,下一个使用先前的结果。
其次,扩展方法只是静态方法调用的C#糖,在表达式树中它们必须作为静态方法被“调用”。
因此,调用
public static IUpdateConfiguration<T> OwnedEntity<T, T2>(this IUpdateConfiguration<T> config, Expression<Func<T, T2>> expression);
可以这样
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);
}
而有问题的 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);
}
我在其他地方问过一个具体问题,但在没有回应和一些调查之后,我将其归结为更通用的问题,但我仍在努力构建表达式树。
我正在使用第三方库,它使用接口和扩展方法进行一些映射。这些映射被指定为表达式树,我想要做的是从字符串值构建该表达式树。
扩展方法签名:
public static T UpdateGraph<T>(this DbContext context, T entity, Expression<Func<IUpdateConfiguration<T>, object>> mapping = null, bool allowDelete = true) where T : class, new();
接口IUpdateConfiguration只是一个标记接口,但有以下扩展方法:
public static class UpdateConfigurationExtensions
{
public static IUpdateConfiguration<T> OwnedCollection<T, T2>(this IUpdateConfiguration<T> config, Expression<Func<T, ICollection<T2>>> expression);
public static IUpdateConfiguration<T> OwnedCollection<T, T2>(this IUpdateConfiguration<T> config, Expression<Func<T, ICollection<T2>>> expression, Expression<Func<IUpdateConfiguration<T2>, object>> mapping);
public static IUpdateConfiguration<T> OwnedEntity<T, T2>(this IUpdateConfiguration<T> config, Expression<Func<T, T2>> expression);
public static IUpdateConfiguration<T> OwnedEntity<T, T2>(this IUpdateConfiguration<T> config, Expression<Func<T, T2>> expression, Expression<Func<IUpdateConfiguration<T2>, object>> mapping);
}
使用示例实体:
public class Person
{
public Car Car {get;set;}
public House House {get;set;}
}
所以正常的显式用法是:
dbContext.UpdateGraph(person, mapping => mapping.OwnedEntity(p => p.House).OwnedEntity(p=> p.Car));
我需要做的是从 属性 个名称列表中建立映射,
var props = {"Car","House"}
dbContext.UpdateGraph(person, buildExpressionFromStrings<Person>(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.
}
实际上,真实世界的代码比这更复杂(需要处理递归和子 properties/mappings),但我认为一旦我为一个级别构建了表达式,我就可以对其进行排序.一天多来我一直在努力整理头发,试图对此进行排序...为了提供一些背景信息,我正在使用 entity framework 和一些配置来定义聚合根。
我将 dynamic object creating with given props. And I use DynamicQueryable 的对象生成器用于基于字符串的表达式。
没什么好说的。这里
mapping => mapping.OwnedEntity(p => p.House).OwnedEntity(p=> p.Car)
lambda 表达式 body 的部分不是 lambda 表达式,而只是链式方法调用表达式,第一个使用 lambda 表达式参数,下一个使用先前的结果。
其次,扩展方法只是静态方法调用的C#糖,在表达式树中它们必须作为静态方法被“调用”。
因此,调用
public static IUpdateConfiguration<T> OwnedEntity<T, T2>(this IUpdateConfiguration<T> config, Expression<Func<T, T2>> expression);
可以这样
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);
}
而有问题的 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);
}