如何拆分多个级别的成员访问
本文关键字:成员 访问 何拆分 拆分 | 更新日期: 2023-09-27 17:59:01
让我们假设我定义了这些伪类:
public class MyObject
{
public InterestingFact InterestingFact { get; set; }
}
public class InterestingFact
{
public Detail Detail { get; set; }
}
public class Detail
{
public string Information { get; set; }
}
我还有一个MyObject
:的实例
var obj = new MyObject() { InterestingFact = new InterestingFact() };
如果我想尝试访问Information
属性,我可以这样做:
string info = null;
if (obj != null
&& obj.InterestingFact != null
&& obj.InterestingFact.Detail != null)
{
info = obj.InterestingFact.Detail.Information;
}
为了这个讨论,忽略了德米特定律,每次我想访问我所拥有的物体深处的东西时,这并不是一件很有趣的事。当然,我可以创建一个扩展方法:
public static U NullOr<T, U>(this T target, Func<T, U> selector)
{
if (EqualityComparer<T>.Default.Equals(target, default(T)))
{
return default(U);
}
return selector(target);
}
这使得选择数据变得更容易:
// Here I have a null of type string.
var info = obj.NullOr(o => o.InterestingFact).NullOr(f => f.Detail).NullOr(d => d.Information);
然而,这仍然有点冗长。理想情况下,我想做一些更像这样的事情:
// Here I should still have a null of type string.
var info = obj.NullOr(o => o.InterestingFact.Detail.Information);
我从未使用过Expression
;如果我接受Expression<Func<T, U>>
而不是NullOr
中的Func<T, U>
,在我看来,这是一个成员访问,而不是三个成员访问。有没有办法解决上述问题,或者这种提法遥不可及?
(当然,还有一个问题是,上一个公式认为,发送的表达式可能不仅仅是链式成员访问。)
使用扩展方法实现所需结果的最简单方法如下。
public static class ExtensionMethods
{
public static TR DefaultIfNull<T, TR>(this T source, Expression<Func<T, TR>> expr, TR defaultValue = default(TR))
{
TR result = defaultValue;
try
{
result = expr.Compile().Invoke(source);
}
catch (NullReferenceException)
{
// DO NOTHING
}
return result;
}
}
下面是上面的一些用法示例
var info1 = obj.DefaultIfNull(x => x.InterestingFact.ToString(), "Null1");
var info2 = obj.DefaultIfNull(x => x.InterestingFact.Detail.ToString(), "Null2");
var info3 = obj.DefaultIfNull(x => x.InterestingFact.Detail.Information);
请注意,这不是BEST解决方案,因为它不检查单个表达式节点是否为null,因此,如果树中的任何节点碰巧在内部生成NullReferenceException
,则将返回默认值,而不是抛出异常。然而,对于一般和简单的使用来说,这可能是最佳解决方案(主要是因为它的简单性)。