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