C# 4.0 如何在表达式(C#4.0)中展开(内联)属性?

C# 4.0 如何在表达式(C#4.0)中展开(内联)属性?,c#-4.0,expression-trees,C# 4.0,Expression Trees,我有一个表达形式: Expression<Func<ShowParticipant, bool>> expr = z => z.Show.OrgName == "xyz"; 感谢您的回复 Anand.表达式树本身无法做到这一点,因为表达式树无法知道调用OrgName属性在幕后的作用 但是,如果要在属性上放置一个属性,那么某些工厂可能会将对property1(“OrgName”)的调用替换为属性路径Organization.Name 下面是示例代码 stat

我有一个表达形式:

Expression<Func<ShowParticipant, bool>> expr = z => z.Show.OrgName == "xyz";
感谢您的回复


Anand.

表达式树本身无法做到这一点,因为表达式树无法知道调用OrgName属性在幕后的作用

但是,如果要在属性上放置一个属性,那么某些工厂可能会将对property1(“OrgName”)的调用替换为属性路径Organization.Name

下面是示例代码

    static void Main(string[] args)
    {
        Company company = new Company { Organization = { Name = "Microsoft" } };
        Expression<Func<Company, int>> lambdaExpression = c => c.OrgName.Length;
        var expanded = Expand(lambdaExpression);
    }

    private static Expression<Func<TSource, TResult>> Expand<TSource, TResult>(Expression<Func<TSource, TResult>> lambdaExpression)
    {
        Expression expanded = GetExpandedExpression(lambdaExpression.Body);
        if (Object.ReferenceEquals(lambdaExpression.Body, expanded))
        {
            return lambdaExpression;
        }
        return Expression.Lambda<Func<TSource, TResult>>(
            expanded,
            lambdaExpression.Parameters
        );
    }

    private static Expression GetExpandedExpression(Expression expression)
    {
        Expression expandedContainer;
        switch (expression.NodeType)
        {
            case ExpressionType.MemberAccess:
                MemberExpression memberExpression = (MemberExpression)expression;
                if (memberExpression.Expression != null)
                {
                    expandedContainer = GetExpandedExpression(memberExpression.Expression);
                    PropertyPathAttribute attribute = memberExpression.Member.GetCustomAttributes(typeof(PropertyPathAttribute), false).Cast<PropertyPathAttribute>().FirstOrDefault();
                    if (attribute != null && !String.IsNullOrEmpty(attribute.Path))
                    {
                        string[] parts = attribute.Path.Split('.');
                        expression = expandedContainer;
                        for (int i = 0; i < parts.Length; i++)
                        {
                            string part = parts[i];
                            expression = Expression.MakeMemberAccess(
                                expression,
                                (MemberInfo)expression.Type.GetProperty(part, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ??
                                    expression.Type.GetField(part, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                            );
                        }
                    }
                    else if (!Object.ReferenceEquals(expandedContainer, memberExpression.Expression))
                    {
                        return Expression.MakeMemberAccess(
                            expandedContainer,
                            memberExpression.Member
                        );
                    }
                }
                break;
            case ExpressionType.ArrayLength:
                UnaryExpression unaryExpression = (UnaryExpression)expression;
                if (!Object.ReferenceEquals(expandedContainer = GetExpandedExpression(unaryExpression.Operand), unaryExpression.Operand))
                {
                    return Expression.ArrayLength(expandedContainer);
                }
                break;
        }
        return expression;
    }

    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
    public sealed class PropertyPathAttribute : Attribute
    {
        private readonly string _path;

        public string Path
        {
            get
            {
                return this._path;
            }
        }

        public PropertyPathAttribute(string path)
        {
            this._path = path;
        }
    }

    public class Organization
    {
        public string Name { get; set; }
    }

    public class Company
    {
        [PropertyPath("Organization.Name")]
        public string OrgName
        {
            get
            {
                return this.Organization.Name;
            }
            set
            {
                this.Organization.Name = value;
            }
        }

        public Organization Organization { get; private set; }

        public Company()
        {
            this.Organization = new Organization();
        }
    }
static void Main(字符串[]args)
{
公司=新公司{Organization={Name=“Microsoft”};
表达式lambdaExpression=c=>c.OrgName.Length;
var expanded=Expand(lambdaExpression);
}
专用静态表达式扩展(表达式lambdaExpression)
{
Expression expanded=GetExpandedExpression(lambdaExpression.Body);
if(Object.ReferenceEquals(lambdaExpression.Body,展开))
{
返回lambdaExpression;
}
返回表达式.Lambda(
扩大,
lambdaExpression.Parameters
);
}
私有静态表达式GetExpandedExpression(表达式)
{
表达式扩展容器;
开关(表达式.节点类型)
{
case ExpressionType.MemberAccess:
MemberExpression MemberExpression=(MemberExpression)表达式;
if(memberExpression.Expression!=null)
{
expandedContainer=GetExpandedExpression(memberExpression.Expression);
PropertyPathAttribute属性=memberExpression.Member.GetCustomAttributes(typeof(PropertyPathAttribute),false).Cast().FirstOrDefault();
if(attribute!=null&&!String.IsNullOrEmpty(attribute.Path))
{
string[]parts=attribute.Path.Split('.');
表达式=expandedContainer;
对于(int i=0;i
表达式树本身无法做到这一点,因为表达式树无法知道调用OrgName属性在幕后的作用

但是,如果要在属性上放置一个属性,那么某些工厂可能会将对property1(“OrgName”)的调用替换为属性路径Organization.Name

下面是示例代码

    static void Main(string[] args)
    {
        Company company = new Company { Organization = { Name = "Microsoft" } };
        Expression<Func<Company, int>> lambdaExpression = c => c.OrgName.Length;
        var expanded = Expand(lambdaExpression);
    }

    private static Expression<Func<TSource, TResult>> Expand<TSource, TResult>(Expression<Func<TSource, TResult>> lambdaExpression)
    {
        Expression expanded = GetExpandedExpression(lambdaExpression.Body);
        if (Object.ReferenceEquals(lambdaExpression.Body, expanded))
        {
            return lambdaExpression;
        }
        return Expression.Lambda<Func<TSource, TResult>>(
            expanded,
            lambdaExpression.Parameters
        );
    }

    private static Expression GetExpandedExpression(Expression expression)
    {
        Expression expandedContainer;
        switch (expression.NodeType)
        {
            case ExpressionType.MemberAccess:
                MemberExpression memberExpression = (MemberExpression)expression;
                if (memberExpression.Expression != null)
                {
                    expandedContainer = GetExpandedExpression(memberExpression.Expression);
                    PropertyPathAttribute attribute = memberExpression.Member.GetCustomAttributes(typeof(PropertyPathAttribute), false).Cast<PropertyPathAttribute>().FirstOrDefault();
                    if (attribute != null && !String.IsNullOrEmpty(attribute.Path))
                    {
                        string[] parts = attribute.Path.Split('.');
                        expression = expandedContainer;
                        for (int i = 0; i < parts.Length; i++)
                        {
                            string part = parts[i];
                            expression = Expression.MakeMemberAccess(
                                expression,
                                (MemberInfo)expression.Type.GetProperty(part, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ??
                                    expression.Type.GetField(part, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                            );
                        }
                    }
                    else if (!Object.ReferenceEquals(expandedContainer, memberExpression.Expression))
                    {
                        return Expression.MakeMemberAccess(
                            expandedContainer,
                            memberExpression.Member
                        );
                    }
                }
                break;
            case ExpressionType.ArrayLength:
                UnaryExpression unaryExpression = (UnaryExpression)expression;
                if (!Object.ReferenceEquals(expandedContainer = GetExpandedExpression(unaryExpression.Operand), unaryExpression.Operand))
                {
                    return Expression.ArrayLength(expandedContainer);
                }
                break;
        }
        return expression;
    }

    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
    public sealed class PropertyPathAttribute : Attribute
    {
        private readonly string _path;

        public string Path
        {
            get
            {
                return this._path;
            }
        }

        public PropertyPathAttribute(string path)
        {
            this._path = path;
        }
    }

    public class Organization
    {
        public string Name { get; set; }
    }

    public class Company
    {
        [PropertyPath("Organization.Name")]
        public string OrgName
        {
            get
            {
                return this.Organization.Name;
            }
            set
            {
                this.Organization.Name = value;
            }
        }

        public Organization Organization { get; private set; }

        public Company()
        {
            this.Organization = new Organization();
        }
    }
static void Main(字符串[]args)
{
公司=新公司{Organization={Name=“Microsoft”};
表达式lambdaExpression=c=>c.OrgName.Length;
var expanded=Expand(lambdaExpression);
}
专用静态表达式扩展(表达式lambdaExpression)
{
Expression expanded=GetExpandedExpression(lambdaExpression.Body);
if(Object.ReferenceEquals(lambdaExpression.Body,展开))
{
返回lambdaExpression;
}
返回表达式.Lambda(
扩大,
lambdaExpression.Parameters
);
}
私有静态表达式GetExpandedExpression(表达式)
{
表达式扩展容器;
开关(表达式.节点类型)
{
case ExpressionType.MemberAccess:
MemberExpression MemberExpression=(MemberExpression)表达式;
if(memberExpression.Expression!=null)
{
expandedContainer=GetExpandedExpression(memberExpression.Expression);
PropertyPathAttribute属性=memberExpression.Member.GetCustomAttributes(typeof(PropertyPathAttribute),false
    static void Main(string[] args)
    {
        Company company = new Company { Organization = { Name = "Microsoft" } };
        Expression<Func<Company, int>> lambdaExpression = c => c.OrgName.Length;
        var expanded = Expand(lambdaExpression);
    }

    private static Expression<Func<TSource, TResult>> Expand<TSource, TResult>(Expression<Func<TSource, TResult>> lambdaExpression)
    {
        Expression expanded = GetExpandedExpression(lambdaExpression.Body);
        if (Object.ReferenceEquals(lambdaExpression.Body, expanded))
        {
            return lambdaExpression;
        }
        return Expression.Lambda<Func<TSource, TResult>>(
            expanded,
            lambdaExpression.Parameters
        );
    }

    private static Expression GetExpandedExpression(Expression expression)
    {
        Expression expandedContainer;
        switch (expression.NodeType)
        {
            case ExpressionType.MemberAccess:
                MemberExpression memberExpression = (MemberExpression)expression;
                if (memberExpression.Expression != null)
                {
                    expandedContainer = GetExpandedExpression(memberExpression.Expression);
                    PropertyPathAttribute attribute = memberExpression.Member.GetCustomAttributes(typeof(PropertyPathAttribute), false).Cast<PropertyPathAttribute>().FirstOrDefault();
                    if (attribute != null && !String.IsNullOrEmpty(attribute.Path))
                    {
                        string[] parts = attribute.Path.Split('.');
                        expression = expandedContainer;
                        for (int i = 0; i < parts.Length; i++)
                        {
                            string part = parts[i];
                            expression = Expression.MakeMemberAccess(
                                expression,
                                (MemberInfo)expression.Type.GetProperty(part, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ??
                                    expression.Type.GetField(part, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                            );
                        }
                    }
                    else if (!Object.ReferenceEquals(expandedContainer, memberExpression.Expression))
                    {
                        return Expression.MakeMemberAccess(
                            expandedContainer,
                            memberExpression.Member
                        );
                    }
                }
                break;
            case ExpressionType.ArrayLength:
                UnaryExpression unaryExpression = (UnaryExpression)expression;
                if (!Object.ReferenceEquals(expandedContainer = GetExpandedExpression(unaryExpression.Operand), unaryExpression.Operand))
                {
                    return Expression.ArrayLength(expandedContainer);
                }
                break;
        }
        return expression;
    }

    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
    public sealed class PropertyPathAttribute : Attribute
    {
        private readonly string _path;

        public string Path
        {
            get
            {
                return this._path;
            }
        }

        public PropertyPathAttribute(string path)
        {
            this._path = path;
        }
    }

    public class Organization
    {
        public string Name { get; set; }
    }

    public class Company
    {
        [PropertyPath("Organization.Name")]
        public string OrgName
        {
            get
            {
                return this.Organization.Name;
            }
            set
            {
                this.Organization.Name = value;
            }
        }

        public Organization Organization { get; private set; }

        public Company()
        {
            this.Organization = new Organization();
        }
    }
public class ExpressionExpander : ExpressionVisitor
{
    private Dictionary<Expression, Expression> parameterMap = new Dictionary<Expression, Expression>();

    protected override Expression VisitParameter(ParameterExpression node)
    {
        if (parameterMap.ContainsKey(node))
            return parameterMap[node];

        return node;
    }

    protected override Expression VisitMember(MemberExpression node)
    {
            var newObj = Visit(node.Expression);
            if (NeedsInlineExpansion(newObj.Type, node.Member.Name))
            {
                LambdaExpression exp = GetPropertyTransform();

                if (parameterMap.ContainsKey(node.Expression))
                    parameterMap.Add(exp.Parameters[0], node.Expression);

                var visitedExp = Visit(exp.Body);
                var memExp = (MemberExpression)visitedExp;

                parameterMap.Add(node, memExp);
                return memExp;
            }
            else
            {
                var newMember = newObj.Type.GetMember(node.Member.Name).First();
                var newMemberAccessExpr = Expression.MakeMemberAccess(newObj, newMember);
                parameterMap.Add(node, newMemberAccessExpr);
                return newMemberAccessExpr;
            }
    }

    private bool NeedsInlineExpansion(Type type, string coreMemberName)
    {
        // Figure out way to determine if the property needs to be flattened out...
        // may be using attribute on Property
    }

    private LambdaExpression GetPropertyTransform()
    {
        // this is hardcoded right now, but represents some mechanism of getting a lambda 
        // returned for property in question...
        Expression<Func<Show, string>> exp = z => z.Organization.Name;
        var lambda = (LambdaExpression)exp;
        return lambda;
    }
}
        Expression<Func<ShowParticipant, bool>> expr1 = z => z.Show.OrgName == "xyz";
        ExpressionExpander expander = new ExpressionExpander();
        var inlineExpanded = expander.Visit(expr1);