Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#检查属性';的属性为空_C#_Nullreferenceexception_Nullable_Null Conditional Operator - Fatal编程技术网

C#检查属性';的属性为空

C#检查属性';的属性为空,c#,nullreferenceexception,nullable,null-conditional-operator,C#,Nullreferenceexception,Nullable,Null Conditional Operator,在C#中,假设您希望在本例中从PropertyC中提取一个值,ObjectA、PropertyA和PropertyB都可以为null ObjectA.PropertyA.PropertyB.PropertyC 如何用最少的代码安全地获取PropertyC 现在我要检查一下: if(ObjectA != null && ObjectA.PropertyA !=null && ObjectA.PropertyA.PropertyB != null) { //

在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;
}
这样做会更好(伪代码)

使用空合并运算符可能会进一步崩溃


EDIT最初我说我的第二个示例类似于js,但我将其改为psuedo代码,因为有人正确指出它在js中不起作用。

我将使用与可空类型类似的模式,在PropertyA类型中编写您自己的方法(或扩展方法,如果它不是您的类型)

class PropertyAType
{
   public PropertyBType PropertyB {get; set; }

   public PropertyBType GetPropertyBOrDefault()
   {
       return PropertyB != null ? PropertyB : defaultValue;
   }
}

你这样做是正确的

您可以使用所述的技巧,使用Linq表达式:

int value = ObjectA.NullSafeEval(x => x.PropertyA.PropertyB.PropertyC, 0);
但是手动检查每个属性要慢得多…

这是不可能的。
ObjectA.PropertyA.PropertyB
将失败,如果
ObjectA
由于空解引用而为空,这是一个错误

if(ObjectA!=null&&ObjectA.PropertyA
…由于短路而工作,即
ObjectA.PropertyA
如果
ObjectA
null
,则永远不会检查

您提出的第一种方法是最好的,也是最明确的。如果您可以尝试重新设计,而不必依赖太多的空值。

此代码是“最少的代码”,但不是最佳实践:

try
{
    return ObjectA.PropertyA.PropertyB.PropertyC;
}
catch(NullReferenceException)
{
     return null;
}

你能给你的类添加一个方法吗?如果不能,你考虑过使用扩展方法吗?你可以为你的对象类型创建一个名为
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;
    }
}
用法:

int val = ObjectA.GetPropC(0); // will return PropC value, or 0 (defaltValue)
顺便说一下,这假设您使用的是.NET 3或更高版本。

您可以这样做:

class ObjectAType
{
    public int PropertyC
    {
        get
        {
            if (PropertyA == null)
                return 0;
            if (PropertyA.PropertyB == null)
                return 0;
            return PropertyA.PropertyB.PropertyC;
        }
    }
}



if (ObjectA != null)
{
    int value = ObjectA.PropertyC;
    ...
}
或者更好的可能是:

private static int GetPropertyC(ObjectAType objectA)
{
    if (objectA == null)
        return 0;
    if (objectA.PropertyA == null)
        return 0;
    if (objectA.PropertyA.PropertyB == null)
        return 0;
    return objectA.PropertyA.PropertyB.PropertyC;
}


int value = GetPropertyC(ObjectA);

重构以观察

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

var x = (((objectA ?? A.Empty).PropertyOfB ?? B.Empty).PropertyOfC ?? C.Empty).PropertyOfString;
我是C的忠实粉丝,但在新Java(1.7?)中,一个非常好的东西是。?运算符:

 var x = objectA.?PropertyOfB.?PropertyOfC.?PropertyOfString;

显然,您正在寻找可为空的Monad

string result = new A().PropertyB.PropertyC.Value;
变成

string result = from a in new A()
                from b in a.PropertyB
                from c in b.PropertyC
                select c.Value;
如果任何可为null的属性为null,则返回
null
;否则返回
value
的值

class A { public B PropertyB { get; set; } }
class B { public C PropertyC { get; set; } }
class C { public string Value { get; set; } }

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);
    }
}
公共静态类NullableExtensions
{
公共静态TResult SelectMany(
这个兜售者的消息来源,
Func内部选择器,
Func结果选择器)
兜售者:班级
TInner在哪里上课
结果:在哪里上课
{
if(source==null)返回null;
TInner内部=内部选择器(源);
if(inner==null)返回null;
返回结果选择器(源,内部);
}
}

一旦你克服了lambda gobbly的问题,这种方法就相当简单了:

public static TProperty GetPropertyOrDefault<TObject, TProperty>(this TObject model, Func<TObject, TProperty> valueFunc)  
                                                        where TObject : class
    {
        try
        {
            return valueFunc.Invoke(model);
        }
        catch (NullReferenceException nex)
        {
            return default(TProperty);
        }
    }

??
(null合并运算符)意味着如果第一个参数是
null
,则返回第二个参数。

当我需要这样链接调用时,我依赖于我创建的帮助器方法TryGet():


刚刚无意中通过了这篇文章

不久前,我在Visual Studio Connect上建议添加一个新的
操作符

这需要框架团队做一些工作,但不需要改变语言,只需要做一些编译器的魔术

将其写入此代码

Func<string> _get_default = () => "no product defined"; 
string product_name = Order == null 
    ? _get_default.Invoke() 
    : Order.OrderDetails[0] == null 
        ? _get_default.Invoke() 
        : Order.OrderDetails[0].Product == null 
            ? _get_default.Invoke() 
            : Order.OrderDetails[0].Product.Name ?? _get_default.Invoke()

您可以使用以下扩展,我认为它非常好:

/// <summary>
/// Simplifies null checking
/// </summary>
public static TR Get<TF, TR>(TF t, Func<TF, TR> f)
    where TF : class
{
    return t != null ? f(t) : default(TR);
}

/// <summary>
/// Simplifies null checking
/// </summary>
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
/// </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);
}

短扩展方法:

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);
}
这是一种简单的扩展方法,您可以在

编辑:

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

更新2014:C#6有一个新的操作符
?。
各种称为“安全导航”或“空传播”的操作符

parent?.child
详情请阅读

这一直是一个非常受欢迎的要求

我编写了一个接受默认值的方法,下面是如何使用它:

var teacher = new Teacher();
return teacher.GetProperty(t => t.Name);
return teacher.GetProperty(t => t.Name, "Default name");
代码如下:

public static class Helper
{
    /// <summary>
    /// Gets a property if the object is not null.
    /// var teacher = new Teacher();
    /// return teacher.GetProperty(t => t.Name);
    /// return teacher.GetProperty(t => t.Name, "Default name");
    /// </summary>
    public static TSecond GetProperty<TFirst, TSecond>(this TFirst item1,
        Func<TFirst, TSecond> getItem2, TSecond defaultValue = default(TSecond))
    {
        if (item1 == null)
        {
            return defaultValue;
        }

        return getItem2(item1);
    }
}
公共静态类帮助器
{
/// 
///如果对象不为null,则获取属性。
///var teacher=新教师();
///返回teacher.GetProperty(t=>t.Name);
///返回teacher.GetProperty(t=>t.Name,“默认名称”);
/// 
公共静态TSecond GetProperty(此TFirst item1,
Func getItem2,TSecond defaultValue=default(TSecond))
{
if(item1==null)
{
返回默认值;
}
返回getItem2(item1);
}
}
在C#6中,您可以使用。因此原始测试将是:

int? value = objectA?.PropertyA?.PropertyB?.PropertyC;

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

例如,不使用

if (Person != null && Person.Contact!=null && Person.Contact.Address!= null && Person.Contact.Address.City != null)
{ 
  var city = person.contact.address.city;
}
您只需使用

var city = person?.contact?.address?.city;
我希望这对某人有帮助


更新:

你现在可以这样做了

 var city = (Person != null)? 
           ((Person.Contact!=null)? 
              ((Person.Contact.Address!= null)?
                      ((Person.Contact.Address.City!=null)? 
                                 Person.Contact.Address.City : null )
                       :null)
               :null)
            : null;

我不明白你的js示例是如何工作的。你应该得到一个“预期对象”每当
ObjectA
PropertyA
为空时出错。那么,在这种情况下,显然PropertyB永远不能为空。它真的会出现在Java 1.7中吗?在C#中已经有很长一段时间了,但我怀疑它是否会发生……不幸的是,我没有空值。尽管Java语法看起来很好!我将对此进行投票托马斯:上次我检查时,它暗示Java会得到它。但现在我重新检查时,它说:空安全处理:否。因此,我撤销了我的语句,并用一个新的语句替换它:它是为Java 1.7提出的,但没有成功。另外一种方法是monad.netSeems使用的方法,如?。运算符在Visual Stu中DIO 2015,当您只读取属性时,我不认为对象图只有三个层次需要重构。如果OP想要调用一个通过HyrTyc引用的对象的方法,而不是当它只需要CH的属性,那么我同意。
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);
}
PropertyC value = ObjectA.IfNotNull(x => x.PropertyA).IfNotNull(x => x.PropertyB).IfNotNull(x => x.PropertyC);
parent?.child
var teacher = new Teacher();
return teacher.GetProperty(t => t.Name);
return teacher.GetProperty(t => t.Name, "Default name");
public static class Helper
{
    /// <summary>
    /// Gets a property if the object is not null.
    /// var teacher = new Teacher();
    /// return teacher.GetProperty(t => t.Name);
    /// return teacher.GetProperty(t => t.Name, "Default name");
    /// </summary>
    public static TSecond GetProperty<TFirst, TSecond>(this TFirst item1,
        Func<TFirst, TSecond> getItem2, TSecond defaultValue = default(TSecond))
    {
        if (item1 == null)
        {
            return defaultValue;
        }

        return getItem2(item1);
    }
}
int? value = objectA?.PropertyA?.PropertyB?.PropertyC;
if (Person != null && Person.Contact!=null && Person.Contact.Address!= null && Person.Contact.Address.City != null)
{ 
  var city = person.contact.address.city;
}
var city = person?.contact?.address?.city;
 var city = (Person != null)? 
           ((Person.Contact!=null)? 
              ((Person.Contact.Address!= null)?
                      ((Person.Contact.Address.City!=null)? 
                                 Person.Contact.Address.City : null )
                       :null)
               :null)
            : null;