如何分解多个级别的成员访问权限

时间:2014-04-18 03:15:38

标签: c# linq

我们假设我已经定义了这些虚拟类:

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 s;如果我在Expression<Func<T, U>>中使用Func<T, U>代替NullOr,我认为它是一个成员访问而不是三个。有没有办法解决上述问题,或者这种配方是否遥不可及?

(当然,还有一个问题,即上次发送的表达式可能不仅仅是链式成员访问...)

1 个答案:

答案 0 :(得分:0)

关于使用扩展方法获得所需结果的最简单方法如下。

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,则默认将返回value而不是抛出异常。但是,对于一般和简单的用法,这可能是最佳解决方案(主要是因为它的简单性)。