C#优雅的方法来检查属性的属性是否为null

Jon*_*agh 87 c# nullable nullreferenceexception null-conditional-operator

在C#中,假设您希望在此示例中从PropertyC中提取值,而ObjectA,PropertyA和PropertyB都可以为null.

ObjectA.PropertyA.PropertyB.PropertyC

如何使用最少量的代码安全地获取PropertyC?

现在我会检查:

if(ObjectA != null && ObjectA.PropertyA !=null && ObjectA.PropertyA.PropertyB != null)
{
    // safely pull off the value
    int value = objectA.PropertyA.PropertyB.PropertyC;
}
Run Code Online (Sandbox Code Playgroud)

做更像这样的事情会很好(伪代码).

int value = ObjectA.PropertyA.PropertyB ? ObjectA.PropertyA.PropertyB : defaultVal;
Run Code Online (Sandbox Code Playgroud)

可能甚至进一步崩溃与空合并运算符.

编辑最初我说我的第二个例子就像js,但是我把它改成了psuedo-code,因为它被正确地指出它在js中不起作用.

Phi*_*gan 98

在C#6中,您可以使用Null条件运算符.所以最初的测试将是:

int? value = objectA?.PropertyA?.PropertyB?.PropertyC;
Run Code Online (Sandbox Code Playgroud)

  • 如果这些属性中的任何一个为 null,则整个语句返回为“null”。它从左到右开始。如果没有语法糖,这相当于一系列 if 语句,其中 `if(propertyX == null) {value = null} else if (propertyY == null){ value = null} else if......` 以及最终的最后一个表达式是 `if(propertyZ != null) { value = propertyZ }` (3认同)
  • 你能解释一下这是什么吗?如果“ PropertyC”为空,那么“值”等于什么?还是“ PropertyB”为null?如果“对象A”为空怎么办? (2认同)

Krz*_*nek 26

短扩展方法:

public static TResult IfNotNull<TInput, TResult>(this TInput o, Func<TInput, TResult> evaluator)
  where TResult : class where TInput : class
{
  if (o == null) return null;
  return evaluator(o);
}
Run Code Online (Sandbox Code Playgroud)

运用

PropertyC value = ObjectA.IfNotNull(x => x.PropertyA).IfNotNull(x => x.PropertyB).IfNotNull(x => x.PropertyC);
Run Code Online (Sandbox Code Playgroud)

这个简单的扩展方法可以在http://devtalk.net/csharp/chained-null-checks-and-the-maybe-monad/上找到.

编辑:

在使用它之后我认为这个方法的正确名称应该是IfNotNull()而不是原始的With().


Sam*_*Sam 16

你能为你的班级添加一个方法吗?如果没有,您是否考虑过使用扩展方法?您可以为名为的对象类型创建扩展方法GetPropC().

例:

public static class MyExtensions
{
    public static int GetPropC(this MyObjectType obj, int defaltValue)
    {
        if (obj != null && obj.PropertyA != null & obj.PropertyA.PropertyB != null)
            return obj.PropertyA.PropertyB.PropertyC;
        return defaltValue;
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

int val = ObjectA.GetPropC(0); // will return PropC value, or 0 (defaltValue)
Run Code Online (Sandbox Code Playgroud)

顺便说一句,这假设您使用的是.NET 3或更高版本.


Tho*_*que 12

你这样做的方式是正确的.

可以使用Linq表达式使用类似于此处描述的技巧:

int value = ObjectA.NullSafeEval(x => x.PropertyA.PropertyB.PropertyC, 0);
Run Code Online (Sandbox Code Playgroud)

但手动检查每个房产要慢得多......


rta*_*bot 11

重构遵守得墨忒耳定律

  • 我同意@rtalbot(尽管,公平性@Daz Lewis提出了一个4深的例子,因为最后一个项目是KeyValuePair).如果有什么东西搞乱了Customer对象,那么我看不到它通过Address对象看到的业务 - 层次结构.假设您后来确定KeyValuePair对Country属性来说不是一个好主意.在这种情况下,每个人的代码都必须改变.那不是一个好的设计. (3认同)

dtb*_*dtb 9

你显然正在寻找Nullable Monad:

string result = new A().PropertyB.PropertyC.Value;
Run Code Online (Sandbox Code Playgroud)

string result = from a in new A()
                from b in a.PropertyB
                from c in b.PropertyC
                select c.Value;
Run Code Online (Sandbox Code Playgroud)

null如果任何可空属性为null,则返回; 否则,价值Value.

class A { public B PropertyB { get; set; } }
class B { public C PropertyC { get; set; } }
class C { public string Value { get; set; } }
Run Code Online (Sandbox Code Playgroud)

LINQ扩展方法:

public static class NullableExtensions
{
    public static TResult SelectMany<TOuter, TInner, TResult>(
        this TOuter source,
        Func<TOuter, TInner> innerSelector,
        Func<TOuter, TInner, TResult> resultSelector)
        where TOuter : class
        where TInner : class
        where TResult : class
    {
        if (source == null) return null;
        TInner inner = innerSelector(source);
        if (inner == null) return null;
        return resultSelector(source, inner);
    }
}
Run Code Online (Sandbox Code Playgroud)


Bor*_*sky 5

此代码是"代码量最少",但不是最佳实践:

try
{
    return ObjectA.PropertyA.PropertyB.PropertyC;
}
catch(NullReferenceException)
{
     return null;
}
Run Code Online (Sandbox Code Playgroud)

  • 您可能应该捕获NullReferenceException,而不是全部. (2认同)
  • 伙计们,我完全同意你的意见.这种方式远非"优雅",但问题是"最少量的代码",这个条件得以实现. (2认同)

Jus*_*mer 5

假设你有类型的空值,一种方法是:

var x = (((objectA ?? A.Empty).PropertyOfB ?? B.Empty).PropertyOfC ?? C.Empty).PropertyOfString;
Run Code Online (Sandbox Code Playgroud)

我是C#的忠实粉丝,但新Java(1.7?)中的一个非常好的东西是.?运营商:

 var x = objectA.?PropertyOfB.?PropertyOfC.?PropertyOfString;
Run Code Online (Sandbox Code Playgroud)

  • 托马斯:上次我检查了http://tech.puredanger.com/java7/它暗示Java会得到它.但是现在当我重新检查它时说:空安全处理:没有.所以我撤销了我的声明,并用一个新声明替换它:它是为Java 1.7提出的,但没有成功. (3认同)

iYa*_*ee6 5

我在新的 C# 6.0 中看到了一些东西,这是通过使用“?” 而不是检查

例如而不是使用

if (Person != null && Person.Contact!=null && Person.Contact.Address!= null && Person.Contact.Address.City != null)
{ 
  var city = person.contact.address.city;
}
Run Code Online (Sandbox Code Playgroud)

你只需使用

var city = person?.contact?.address?.city;
Run Code Online (Sandbox Code Playgroud)

我希望它对某人有帮助。


更新:

你现在可以这样做

 var city = (Person != null)? 
           ((Person.Contact!=null)? 
              ((Person.Contact.Address!= null)?
                      ((Person.Contact.Address.City!=null)? 
                                 Person.Contact.Address.City : null )
                       :null)
               :null)
            : null;
Run Code Online (Sandbox Code Playgroud)