Dve*_*Dve 30 .net c# logic properties
假设您正在尝试阅读此属性
var town = Staff.HomeAddress.Postcode.Town;
Run Code Online (Sandbox Code Playgroud)
沿链的某处可能存在null.阅读城镇的最佳方式是什么?
我一直在试验几种扩展方法......
public static T2 IfNotNull<T1, T2>(this T1 t, Func<T1, T2> fn) where T1 : class
{
return t != null ? fn(t) : default(T2);
}
var town = staff.HomeAddress.IfNotNull(x => x.Postcode.IfNotNull(y=> y.Town));
Run Code Online (Sandbox Code Playgroud)
要么
public static T2 TryGet<T1, T2>(this T1 t, Func<T1, T2> fn) where T1 : class
{
if (t != null)
{
try
{
return fn(t);
}
catch{ }
}
return default(T2);
}
var town = staff.TryGet(x=> x.HomeAddress.Postcode.Town);
Run Code Online (Sandbox Code Playgroud)
显然,这些只是抽象出逻辑并使代码(一点点)更具可读性.
但是有更好/更有效的方式吗?
编辑:
在我的特定情况下,对象是从WCF服务返回的,我无法控制这些对象的体系结构.
编辑2:
还有这种方法:
public static class Nullify
{
public static TR Get<TF, TR>(TF t, Func<TF, TR> f) where TF : class
{
return t != null ? f(t) : default(TR);
}
public static TR Get<T1, T2, TR>(T1 p1, Func<T1, T2> p2, Func<T2, TR> p3)
where T1 : class
where T2 : class
{
return Get(Get(p1, p2), p3);
}
/// <summary>
/// Simplifies null checking as for the pseudocode
/// var r = Pharmacy?.GuildMembership?.State?.Name
/// can be written as
/// var r = Nullify( Pharmacy, p => p.GuildMembership, g => g.State, s => s.Name );
/// </summary>
public static TR Get<T1, T2, T3, TR>(T1 p1, Func<T1, T2> p2, Func<T2, T3> p3, Func<T3, TR> p4)
where T1 : class
where T2 : class
where T3 : class
{
return Get(Get(Get(p1, p2), p3), p4);
}
}
Run Code Online (Sandbox Code Playgroud)
来自这篇文章http://qualityofdata.com/2011/01/27/nullsafe-dereference-operator-in-c/
Ode*_*ded 19
var town = Staff.GetTown();
Run Code Online (Sandbox Code Playgroud)
并在Staff:
string GetTown()
{
HomeAddress.GetTown();
}
Run Code Online (Sandbox Code Playgroud)
并在HomeAddress:
string GetTown()
{
PostCode.GetTown();
}
Run Code Online (Sandbox Code Playgroud)
并在PostCode:
string GetTown()
{
Town.GetTownName();
}
Run Code Online (Sandbox Code Playgroud)
更新:
由于您无法控制此情况,因此可以使用短路评估:
if(Staff != null
&& Staff.HomeAddress != null
&& Staff.HomeAddress.PostCode != null
&& Staff.HomeAddress.PostCode.Town != null)
{
var town = Staff.HomeAddress.Postcode.Town;
}
Run Code Online (Sandbox Code Playgroud)
Ani*_*Ani 10
我同意Oded的说法,这违反了得墨忒耳法则.
我对你的问题很感兴趣,所以我写了一个穷人的"Null-Safe Evaluate"扩展方法和表达式树,只是为了好玩.这应该为您提供紧凑的语法来表达所需的语义.
请不要在生产代码中使用它.
用法:
var town = Staff.NullSafeEvaluate(s => s.HomeAddress.Postcode.Town);
Run Code Online (Sandbox Code Playgroud)
这将连续评估:
Staff
Staff.HomeAddress
Staff.HomeAddress.Postcode
Staff.HomeAddress.Postcode.Town
Run Code Online (Sandbox Code Playgroud)
(缓存并重用中间表达式的值以生成下一个)
如果遇到null引用,则返回类型的默认值Town.否则,它返回完整表达式的值.
(未经过彻底测试,可以在性能方面进行改进,不支持实例方法.仅限POC.)
public static TOutput NullSafeEvaluate<TInput, TOutput>
(this TInput input, Expression<Func<TInput, TOutput>> selector)
{
if (selector == null)
throw new ArgumentNullException("selector");
if (input == null)
return default(TOutput);
return EvaluateIterativelyOrDefault<TOutput>
(input, GetSubExpressions(selector));
}
private static T EvaluateIterativelyOrDefault<T>
(object rootObject, IEnumerable<MemberExpression> expressions)
{
object currentObject = rootObject;
foreach (var sourceMemEx in expressions)
{
// Produce next "nested" member-expression.
// Reuse the value of the last expression rather than
// re-evaluating from scratch.
var currentEx = Expression.MakeMemberAccess
(Expression.Constant(currentObject), sourceMemEx.Member);
// Evaluate expression.
var method = Expression.Lambda(currentEx).Compile();
currentObject = method.DynamicInvoke();
// Expression evaluates to null, return default.
if (currentObject == null)
return default(T);
}
// All ok.
return (T)currentObject;
}
private static IEnumerable<MemberExpression> GetSubExpressions<TInput, TOutput>
(Expression<Func<TInput, TOutput>> selector)
{
var stack = new Stack<MemberExpression>();
var parameter = selector.Parameters.Single();
var currentSubEx = selector.Body;
// Iterate through the nested expressions, "reversing" their order.
// Stop when we reach the "root", which must be the sole parameter.
while (currentSubEx != parameter)
{
var memEx = currentSubEx as MemberExpression;
if (memEx != null)
{
// Valid member-expression, push.
stack.Push(memEx);
currentSubEx = memEx.Expression;
}
// It isn't a member-expression, it must be the parameter.
else if (currentSubEx != parameter)
{
// No, it isn't. Throw, don't support arbitrary expressions.
throw new ArgumentException
("Expression not of the expected form.", "selector");
}
}
return stack;
}
Run Code Online (Sandbox Code Playgroud)
var town = "DefaultCity";
if (Staff != null &&
Staff.HomeAddress != null &&
Staff.HomeAddress.Postcode != null &&
Staff.HomeAddress.Postcode.Town != null)
{
town = Staff.HomeAddress.Postcode.Town;
}
Run Code Online (Sandbox Code Playgroud)
根据封装,类始终有责任在返回字段(和属性)之前对其字段(和属性)进行适当的验证(即空检查)。因此,每个对象都对其字段负责,您可以选择返回 null、空字符串,或者引发异常并在链中向上一级进行处理。尝试解决这个问题就像尝试解决封装一样。
| 归档时间: |
|
| 查看次数: |
1030 次 |
| 最近记录: |