Gid*_*sey 4 c# null properties chaining c#-4.0
我有一些代码在长属性链的末尾提取一个值,其中任何一个属性都可以为null.
例如:
var value = prop1.prop2.prop3.prop4;
Run Code Online (Sandbox Code Playgroud)
为了在prop1中处理null的可能性,我必须写:
var value = prop1 == null ? null : prop1.prop2.prop3.prop4;
Run Code Online (Sandbox Code Playgroud)
为了在prop1和prop2中处理null的可能性,我必须写:
var value = prop1 == null
? null
: prop1.prop2 == null ? null : prop1.prop2.prop3.prop4;
Run Code Online (Sandbox Code Playgroud)
要么
var value = prop1 != null && prop1.prop2 != null
? prop1.prop2.prop3.prop4
: null;
Run Code Online (Sandbox Code Playgroud)
如果我想在prop1,prop2和prop3中处理null的可能性,或者甚至更长的属性链,那么代码开始变得非常疯狂.
必须有更好的方法来做到这一点.
如何处理属性链,以便在遇到null时返回null?
有点像?? 运营商会很棒.
从C#6开始,现在使用零条件运算符将解决方案烘焙到语言中; ?.对于属性和?[n]索引器.
空条件运算符只允许您在接收方不为null时访问成员和元素,否则提供null结果:
Run Code Online (Sandbox Code Playgroud)int? length = customers?.Length; // null if customers is null Customer first = customers?[0]; // null if customers is null
我看了一下那里的不同解决方案.他们中的一些使用链接多个扩展方法调用,我不喜欢,因为由于每个链添加的噪声量,它不是非常可读.
我决定使用仅涉及单个扩展方法调用的解决方案,因为它更具可读性.我没有测试性能,但在我的情况下,可读性比性能更重要.
我基于这个解决方案松散地创建了以下类
public static class NullHandling
{
/// <summary>
/// Returns the value specified by the expression or Null or the default value of the expression's type if any of the items in the expression
/// return null. Use this method for handling long property chains where checking each intermdiate value for a null would be necessary.
/// </summary>
/// <typeparam name="TObject"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="instance"></param>
/// <param name="expression"></param>
/// <returns></returns>
public static TResult GetValueOrDefault<TObject, TResult>(this TObject instance, Expression<Func<TObject, TResult>> expression)
where TObject : class
{
var result = GetValue(instance, expression.Body);
return result == null ? default(TResult) : (TResult) result;
}
private static object GetValue(object value, Expression expression)
{
object result;
if (value == null) return null;
switch (expression.NodeType)
{
case ExpressionType.Parameter:
return value;
case ExpressionType.MemberAccess:
var memberExpression = (MemberExpression)expression;
result = GetValue(value, memberExpression.Expression);
return result == null ? null : GetValue(result, memberExpression.Member);
case ExpressionType.Call:
var methodCallExpression = (MethodCallExpression)expression;
if (!SupportsMethod(methodCallExpression))
throw new NotSupportedException(methodCallExpression.Method + " is not supported");
result = GetValue(value, methodCallExpression.Method.IsStatic
? methodCallExpression.Arguments[0]
: methodCallExpression.Object);
return result == null
? null
: GetValue(result, methodCallExpression.Method);
case ExpressionType.Convert:
var unaryExpression = (UnaryExpression) expression;
return Convert(GetValue(value, unaryExpression.Operand), unaryExpression.Type);
default:
throw new NotSupportedException("{0} not supported".FormatWith(expression.GetType()));
}
}
private static object Convert(object value, Type type)
{
return Expression.Lambda(Expression.Convert(Expression.Constant(value), type)).Compile().DynamicInvoke();
}
private static object GetValue(object instance, MemberInfo memberInfo)
{
switch (memberInfo.MemberType)
{
case MemberTypes.Field:
return ((FieldInfo)memberInfo).GetValue(instance);
case MemberTypes.Method:
return GetValue(instance, (MethodBase)memberInfo);
case MemberTypes.Property:
return GetValue(instance, (PropertyInfo)memberInfo);
default:
throw new NotSupportedException("{0} not supported".FormatWith(memberInfo.MemberType));
}
}
private static object GetValue(object instance, PropertyInfo propertyInfo)
{
return propertyInfo.GetGetMethod(true).Invoke(instance, null);
}
private static object GetValue(object instance, MethodBase method)
{
return method.IsStatic
? method.Invoke(null, new[] { instance })
: method.Invoke(instance, null);
}
private static bool SupportsMethod(MethodCallExpression methodCallExpression)
{
return (methodCallExpression.Method.IsStatic && methodCallExpression.Arguments.Count == 1) || (methodCallExpression.Arguments.Count == 0);
}
}
Run Code Online (Sandbox Code Playgroud)
这允许我写下面的内容:
var x = scholarshipApplication.GetValueOrDefault(sa => sa.Scholarship.CostScholarship.OfficialCurrentWorldRanking);
Run Code Online (Sandbox Code Playgroud)
x将包含值的值scholarshipApplication.Scholarship.CostScholarship.OfficialCurrentWorldRanking或者null如果链中的任何属性在此过程中返回null.
| 归档时间: |
|
| 查看次数: |
1258 次 |
| 最近记录: |