具有父空值的变量分辨率

本文关键字:变量 分辨率 空值 | 更新日期: 2023-09-27 18:13:48

我有一个方法,它有很多像这样的语句:

employee.LastName = file.EMPLOYEE.NAME.SUBNAME.FAMILYNAME.NAMEPART1.Value;

(这是一个合成结构。实际的结构基于2.3 HL7 XML,要复杂得多,并且充满了无意义的对象。)

所以我的问题是这些值中的任何一个都可以为空。如果我不检查,那么当我试图获得链中的下一个值时,它将抛出异常。

显然我可以这样做:

if (contract.EMPLOYEE != null)
 if (contract.EMPLOYEE.NAME.SUBNAME != null)
  if (contract.EMPLOYEE.NAME.FAMILYNAME != null)
   if (contract.EMPLOYEE.NAME.FAMILYNAME.NAMEPART1 != null)
     employee.LastName = file.EMPLOYEE.NAME.SUBNAME.FAMILYNAME.NAMEPART1.Value;  

但是每次我需要设置一个值时都要检查很多次。(并且对象树变化很大,所以我不能做一次检查,然后完成系统。)

也许更好的方法是这样做:

try
{
   employee.LastName = file.EMPLOYEE.NAME.SUBNAME.FAMILYNAME.NAMEPART1.Value;
}
catch
{}

(注意,如果值不存在,那么我可以不做任何事情。)

然而,这仍然有点混乱。在这个方法中,我有14项要设置,还有更多的要设置。

是否有一种方法可以将它抽象出来,这样我就可以只做setter和其他一些东西了?

我想到了一个方法调用,可以执行检查/尝试语句,但是如果我传递file.EMPLOYEE.NAME.SUBNAME.FAMILYNAME.NAMEPART1.Value,它将在我传递它时尝试解决它(从而给我一个异常)。

有别的(干净的)方法吗?(也许扩展方法会起作用?)如有任何建议,我将不胜感激。


注意:最后我对每一行都这样做:

try { employee.LastName = file.EMPLOYEE.NAME.SUBNAME.FAMILYNAME.NAMEPART1.Value; } catch (System.NullReferenceException) { }

具有父空值的变量分辨率

这个怎么样:

static class Coalesce
{
    static public TResult C<T, TResult>(this T obj, Func<T, TResult> func)
        where TResult : class
    {
        if (obj != null)
            return func(obj);
        return null;
    }
}

像这样使用:

employee.LastName =
    file.C(o => o.EMPLOYEE)
        .C(o => o.NAME)
        .C(o => o.SUBNAME)
        .C(o => o.FAMILYNAME)
        .C(o => o.NAMEPART1)
        .C(o => o.Value); 

如果链中的任何属性为空,则返回null。

这是受到扩展c#合并操作符的问题的启发,但我使用了一种稍微不同的方法。以稍微长一点的调用语法为代价,我的扩展类更简单,并且对链中的链接数量没有限制。

也可以与??赋值默认值的操作符:

class Foo { public Bar MyBar { get; } }
class Bar { public Baz MyBaz { get; } }
class Baz { }
Baz baz = foo.C(o => o.MyBar).C(o => o.MyBaz) ?? new Baz();