对聚合表达式进行空检查
Null check on aggregate 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();
}
用法
public class A
{
public B BObj { get; set; }
}
public class B
{
public string Name { get; set; }
}
static void Main(string[] args)
{
var obj = new A {BObj = new B {Name ="Test"}};
var obj2 = new A ();
var exp = ExpressionHelper.GetMemberExpressionFunc<A>("BObj.Name");
var test1 = exp(obj);// test1 is "Test"
var test2 = exp(obj2); //throws because BObj is null
}
如果层次结构中的任何 属性 为 null,我希望表达式为 return null,而不是抛出异常。是否可以在聚合表达式中执行此操作?
C# 空条件运算符 ?.
在这种情况下会非常方便。不幸的是,表达式树仍然不支持它,因此实现该目标的一种方法是动态构建等同于手动空检查的方法:
x => x != null && x.Prop1 != null && x.Prop1.Prop2 != null ... ? (object)x.Prop1.Prop2...PropN : null
由于您需要聚合要在最终 Expression.Condition
中使用的成员访问器表达式和条件,因此 Aggregate
方法并不好 - 使用旧的聚合方法 foreach
循环看起来更合适,例如像这样:
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();
我有一个表达式助手来帮助从对象层次结构中获取值
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();
}
用法
public class A
{
public B BObj { get; set; }
}
public class B
{
public string Name { get; set; }
}
static void Main(string[] args)
{
var obj = new A {BObj = new B {Name ="Test"}};
var obj2 = new A ();
var exp = ExpressionHelper.GetMemberExpressionFunc<A>("BObj.Name");
var test1 = exp(obj);// test1 is "Test"
var test2 = exp(obj2); //throws because BObj is null
}
如果层次结构中的任何 属性 为 null,我希望表达式为 return null,而不是抛出异常。是否可以在聚合表达式中执行此操作?
C# 空条件运算符 ?.
在这种情况下会非常方便。不幸的是,表达式树仍然不支持它,因此实现该目标的一种方法是动态构建等同于手动空检查的方法:
x => x != null && x.Prop1 != null && x.Prop1.Prop2 != null ... ? (object)x.Prop1.Prop2...PropN : null
由于您需要聚合要在最终 Expression.Condition
中使用的成员访问器表达式和条件,因此 Aggregate
方法并不好 - 使用旧的聚合方法 foreach
循环看起来更合适,例如像这样:
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();