Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用ExpressionTree创建复杂类型的MemberAccess_C#_Linq_Lambda_Expression_Expression Trees - Fatal编程技术网

C# 使用ExpressionTree创建复杂类型的MemberAccess

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

我想动态地创建一个MemberAccess表达式,其级别比1更深(递归):

我想为Employee中的每个属性和Employee的复杂成员中的每个属性动态创建MemberAccesExpressions列表,结果应该是这样的:

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; }
    }