C# 使用ExpressionTree创建复杂类型的MemberAccess
我想动态地创建一个MemberAccess表达式,其级别比1更深(递归): 我想为Employee中的每个属性和Employee的复杂成员中的每个属性动态创建MemberAccesExpressions列表,结果应该是这样的:C# 使用ExpressionTree创建复杂类型的MemberAccess,c#,linq,lambda,expression,expression-trees,C#,Linq,Lambda,Expression,Expression Trees,我想动态地创建一个MemberAccess表达式,其级别比1更深(递归): 我想为Employee中的每个属性和Employee的复杂成员中的每个属性动态创建MemberAccesExpressions列表,结果应该是这样的: MemberAccesExpression[] { { e => e.Name }, { e => e.Job.Name }, { e => e.Job.Name } } 这是我得到的伪代码: List list = new L
MemberAccesExpression[] {
{ e => e.Name },
{ e => e.Job.Name },
{ e => e.Job.Name }
}
这是我得到的伪代码:
List list = new List();
public Expression<Func<TModel, dynamic>> CreateME<TModel>(TModel model)
{
var type = typeof (TModel);
var properties = type.GetProperties();
foreach (var prop in properties)
{
// I want to ignore collections
if (typeof(ICollection).IsAssignableFrom(prop.PropertyType)) continue;
// Recall for complex property
if (prop.PropertyType.Namespace != "System")
{
// CreateME(model, ) // THIS IS WHEN I DON'T KNOW WHAT TO DO
continue;
}
var param = Expression.Parameter(type, "x");
var memberAccess = Expression.PropertyOrField(param, prop.Name);
list.Add(Expression.Lambda<Func<TModel, dynamic>>(memberAccess, param));
}
}
List List=新列表();
公共表达式CreateME(TModel模型)
{
变量类型=类型(TModel);
var properties=type.GetProperties();
foreach(属性中的var属性)
{
//我想忽略集合
如果(typeof(ICollection).IsAssignableFrom(prop.PropertyType))继续;
//复杂财产的召回
if(prop.PropertyType.Namespace!=“系统”)
{
//CreateME(model,)//这是我不知道该做什么的时候
继续;
}
var param=表达式参数(类型为“x”);
var memberAccess=Expression.PropertyOrField(param,prop.Name);
Add(Expression.Lambda(memberAccess,param));
}
}
如何使其成为递归方法?
我考虑添加一个名为
(TModel模型,表达式>baseMemberAccess=null)
如果成员表达式不为null,则以某种方式将其连接到baseMemberAccess
附言。
有没有更好的方法来确定一个类型是否不是原子类型
(prop.PropertyType.Namespace!=“系统”)
? (不是int、float、string等)
谢谢你的帮助,
亚当
试图将其放得更简单的编辑:
如果要创建成员访问Employee.Name的表达式树,我将执行以下操作:
var param = Expression.Parameter(type, "x");
var memberAccess = Expression.PropertyOrField(param, memberName);
return Expression.Lambda<Func<TModel, TMember>>(memberAccess, param);
var param=Expression.Parameter(类型“x”);
var memberAccess=Expression.PropertyOrField(param,memberName);
返回表达式.Lambda(memberAccess,param);
对于访问Employee.Job.Salary的成员,与此等价的是什么 public IEnumerable CreateME()
public IEnumerable<Expression<Func<TModel, dynamic>>> CreateME<TModel>()
{
var stack = new Stack<StackItem>();
var type = typeof(TModel);
var parameterExpression = Expression.Parameter(type, "x");
stack.Push(new StackItem(typeof(TModel), parameterExpression));
while (stack.Count > 0)
{
var currentItem = stack.Pop();
var properties = currentItem.PropertyType.GetProperties();
foreach (var property in properties)
{
if (IsComplexProperty(property))
stack.Push(new StackItem(property.PropertyType, Expression.PropertyOrField(currentItem.AccessChainExpression, property.Name)));
else
{
yield return GetSimplePropertyExpression<TModel>(parameterExpression, currentItem.AccessChainExpression, property.Name);
}
}
}
}
private static Expression<Func<TModel, dynamic>> GetSimplePropertyExpression<TModel>(ParameterExpression lhs, Expression accessChain, string propertyName)
{
var memberAccess = Expression.Convert(Expression.PropertyOrField(accessChain, propertyName), typeof(object));
return Expression.Lambda<Func<TModel, dynamic>>(memberAccess, lhs);
}
private static bool IsComplexProperty(PropertyInfo p)
{
return !typeof (ICollection).IsAssignableFrom(p.PropertyType) && p.PropertyType.Namespace != "System";
}
class StackItem
{
public StackItem(Type propertyType, Expression accessChainExpression)
{
PropertyType = propertyType;
AccessChainExpression = accessChainExpression;
}
public Type PropertyType { get; private set; }
public Expression AccessChainExpression { get; private set; }
}
{
var stack=新堆栈();
变量类型=类型(TModel);
var parameterExpression=Expression.Parameter(类型为“x”);
Push(新的StackItem(typeof(TModel),parameterExpression));
而(stack.Count>0)
{
var currentItem=stack.Pop();
var properties=currentItem.PropertyType.GetProperties();
foreach(属性中的var属性)
{
if(IsComplexProperty(property))
Push(新的StackItem(property.PropertyType,Expression.propertyField(currentItem.AccessChainExpression,property.Name));
其他的
{
返回GetSimplePropertyExpression(parameterExpression,currentItem.AccessChainExpression,property.Name);
}
}
}
}
私有静态表达式GetSimplePropertyExpression(ParameterExpression lhs、表达式accessChain、字符串propertyName)
{
var memberAccess=Expression.Convert(Expression.PropertyOrField(accessChain,propertyName),typeof(object));
返回表达式.Lambda(memberAccess,lhs);
}
私有静态bool IsComplexProperty(PropertyInfo p)
{
return!typeof(ICollection).IsAssignableFrom(p.PropertyType)&&p.PropertyType.Namespace!=“系统”;
}
类堆栈项
{
公共堆栈项(类型propertyType,表达式accessChainExpression)
{
PropertyType=PropertyType;
AccessChainExpression=AccessChainExpression;
}
公共类型属性类型{get;private set;}
公共表达式AccessChainExpression{get;private set;}
}
我相信这是可以改进的,但这应该是可行的。我感觉到一个问题。你想用你的代码解决什么问题?我不认为不清楚,但我编辑了这个问题,并在最后添加了我的确切问题。他问你想解决的更大的问题是什么?为什么要收集一个对象的所有成员表达式?恐怕这两个都不起作用,或者我不知道如何使用它。在这一行-Expression.Convert(Expression.PropertyOrField(accessChain,propertyName),typeof(object));我得到了这个异常-“'memberName'不是'System.Func`2[TModel,System.Object]类型的成员。”“我只对示例对象进行了测试,您可以发布您用于TModel的实际类定义吗?您的实际TModel是否包含属于Func的属性?
public IEnumerable<Expression<Func<TModel, dynamic>>> CreateME<TModel>()
{
var stack = new Stack<StackItem>();
var type = typeof(TModel);
var parameterExpression = Expression.Parameter(type, "x");
stack.Push(new StackItem(typeof(TModel), parameterExpression));
while (stack.Count > 0)
{
var currentItem = stack.Pop();
var properties = currentItem.PropertyType.GetProperties();
foreach (var property in properties)
{
if (IsComplexProperty(property))
stack.Push(new StackItem(property.PropertyType, Expression.PropertyOrField(currentItem.AccessChainExpression, property.Name)));
else
{
yield return GetSimplePropertyExpression<TModel>(parameterExpression, currentItem.AccessChainExpression, property.Name);
}
}
}
}
private static Expression<Func<TModel, dynamic>> GetSimplePropertyExpression<TModel>(ParameterExpression lhs, Expression accessChain, string propertyName)
{
var memberAccess = Expression.Convert(Expression.PropertyOrField(accessChain, propertyName), typeof(object));
return Expression.Lambda<Func<TModel, dynamic>>(memberAccess, lhs);
}
private static bool IsComplexProperty(PropertyInfo p)
{
return !typeof (ICollection).IsAssignableFrom(p.PropertyType) && p.PropertyType.Namespace != "System";
}
class StackItem
{
public StackItem(Type propertyType, Expression accessChainExpression)
{
PropertyType = propertyType;
AccessChainExpression = accessChainExpression;
}
public Type PropertyType { get; private set; }
public Expression AccessChainExpression { get; private set; }
}