C# 聚合表达式上的Null检查
我有一个表达式助手来帮助从对象层次结构中获取值C# 聚合表达式上的Null检查,c#,expression-trees,C#,Expression Trees,我有一个表达式助手来帮助从对象层次结构中获取值 public static Func<T, object> GetMemberExpressionFunc<T>(string expressionString) { if (string.IsNullOrEmpty(expressionString)) { throw new InvalidOperationException("invalid Expression");
public static Func<T, object> GetMemberExpressionFunc<T>(string expressionString)
{
if (string.IsNullOrEmpty(expressionString))
{
throw new InvalidOperationException("invalid Expression");
}
var parameter = Expression.Parameter(typeof(T));
Expression memberExpression = parameter;
var tokens = expressionString.Split('.');
memberExpression = tokens.Aggregate(memberExpression, Expression.PropertyOrField);
var convertExpression = Expression.Convert(memberExpression, typeof(object));
return Expression.Lambda<Func<T, object>>(convertExpression, parameter)
.Compile();
}
公共静态函数GetMemberExpressionFunc(字符串表达式字符串)
{
if(string.IsNullOrEmpty(expressionString))
{
抛出新的InvalidOperationException(“无效表达式”);
}
var参数=表达式参数(typeof(T));
表达式memberExpression=参数;
var tokens=expressionString.Split('.');
memberExpression=tokens.Aggregate(memberExpression,Expression.PropertyOrField);
var convertExpression=Expression.Convert(memberExpression,typeof(object));
返回表达式.Lambda(convertExpression,parameter)
.Compile();
}
用法
公共A类
{
公共B BObj{get;set;}
}
公共B级
{
公共字符串名称{get;set;}
}
静态void Main(字符串[]参数)
{
var obj=newa{BObj=newb{Name=“Test”};
var obj2=新的A();
var exp=ExpressionHelper.GetMemberExpressionFunc(“BObj.Name”);
var test1=exp(obj);//test1是“Test”
var test2=exp(obj2);//由于BObj为null而引发
}
如果层次结构中的任何属性为null,我希望表达式返回null,而不是引发异常。是否可以在聚合表达式中执行此操作?C#null条件运算符。
在这种情况下非常方便。不幸的是,它在表达式树中仍然不受支持,因此实现这一目标的一种方法是动态构建与手动空值检查等效的方法:
x => x != null && x.Prop1 != null && x.Prop1.Prop2 != null ... ? (object)x.Prop1.Prop2...PropN : null
由于需要聚合成员访问器表达式和要在最终的表达式中使用的条件。条件
,因此聚合
方法不好-使用旧的goodforeach
循环进行聚合看起来更合适,例如:
var parameter = Expression.Parameter(typeof(T));
var nullConst = Expression.Constant(null);
Expression source = parameter, condition = null;
foreach (var memberName in expressionString.Split('.'))
{
var notNull = Expression.NotEqual(source, nullConst);
condition = condition != null ? Expression.AndAlso(condition, notNull) : notNull;
source = Expression.PropertyOrField(source, memberName);
}
source = Expression.Convert(source, typeof(object));
var body = Expression.Condition(condition, source, nullConst);
return Expression.Lambda<Func<T, object>>(body, parameter)
.Compile();
var参数=表达式参数(typeof(T));
var nullConst=表达式常数(null);
表达式源=参数,条件=空;
foreach(expressionString.Split('.')中的var memberName)
{
var notNull=Expression.NotEqual(源,null常量);
条件=条件!=null?表达式。AndAlso(条件,notNull):notNull;
source=Expression.PropertyOrField(source,memberName);
}
source=Expression.Convert(source,typeof(object));
var body=表达式.Condition(Condition,source,nullConst);
返回表达式.Lambda(主体,参数)
.Compile();
您了解聚合方法在做什么吗?据我所知,它只是使用LinqAggregate
方法将一组Expression.PropertyOrField
调用链接在一起。理论上,您可以传入一个不同的方法来执行空检查,然后传递链,但这可能很棘手。我认为在标准循环中执行更具可读性。是的,这里的主要问题是当属性为null时返回null。循环与聚合可读性是一个意见问题,但如果实际问题能够解决,我不介意改变它。
var parameter = Expression.Parameter(typeof(T));
var nullConst = Expression.Constant(null);
Expression source = parameter, condition = null;
foreach (var memberName in expressionString.Split('.'))
{
var notNull = Expression.NotEqual(source, nullConst);
condition = condition != null ? Expression.AndAlso(condition, notNull) : notNull;
source = Expression.PropertyOrField(source, memberName);
}
source = Expression.Convert(source, typeof(object));
var body = Expression.Condition(condition, source, nullConst);
return Expression.Lambda<Func<T, object>>(body, parameter)
.Compile();