C# 尝试枚举自定义类型的列表时引发异常

C# 尝试枚举自定义类型的列表时引发异常,c#,asp.net,entity-framework,asp.net-mvc-4,nullreferenceexception,C#,Asp.net,Entity Framework,Asp.net Mvc 4,Nullreferenceexception,我有两个通过JSON反序列化填充的列表 List<MyType> a = JsonConvert.DeserializeObject<List<MyType>>(jsonstringa); List<MyType> b = JsonConvert.DeserializeObject<List<MyType>>(jsonstringb); 如果其中一个的集合中有项目,则不会出现问题。但是,当列表B中没有项目时,我会在“for

我有两个通过JSON反序列化填充的列表

List<MyType> a = JsonConvert.DeserializeObject<List<MyType>>(jsonstringa);
List<MyType> b = JsonConvert.DeserializeObject<List<MyType>>(jsonstringb);
如果其中一个的集合中有项目,则不会出现问题。但是,当列表B中没有项目时,我会在“foreach”行上抛出一个“objectreference not set to a instance of a Object”异常。但是,列表A不会出现这种情况

为了安全起见,我进一步修改了上述代码,使其看起来如下所示:

if (a.Count > 0)
{
    foreach (MyType myA in a)
    {
       //DO STUFF HERE
    }
}
if (b.Count > 0)
{
    foreach (MyType myB in b)
    {
       //DO STUFF HERE
    }
}
无论是空集合还是包含元素,通过“A”列表的迭代都可以正常进行。如果集合中有元素,则通过“B”列表的迭代再次正常进行,但再次抛出相同的异常,但这次在
(myB.Count)>0
行除外。通过调试,两个集合的Count属性在集合为空时显示“0”(如我所料)

自定义“MyType”类有一个默认构造函数,其中所有非虚拟变量都声明为:

namespace MyApp.Models
{
    public class MyType
    {
        public int ID { get; set; }
        public string Code { get; set; }
        public int ParentID { get; set; }

        [ScriptIgnore(ApplyToOverrides = true)]
        [JsonIgnore]
        public virtual Parent Parent { get; set; }

        public MyType()
        {
            ID = 0;
            Code = null;
            ParentID = 0;
        }
    }
}

我有点不知所措。我还有其他自定义类型在这里也失败了,但是,我怀疑这种相同类型的配对,其中一个通过得很好,另一个抛出异常,希望能帮助有人给我一些关于这种行为的见解。

如果
myB
为null
myB.Count
将抛出异常。您应该首先检查null:

if(myB != null && myB.Count > 0)

为了安全起见,您可能还希望在第一个列表中执行此操作……并且您可以删除
计数检查,这是不必要的。
foreach
在集合为空时不会引发异常,它仅在您尝试迭代null集合时抛出,因为
foreach
调用集合上的
GetEnumerator
方法导致异常。

如果
a
b
为null,则无法对其调用函数。您将得到一个空引用异常。所以检查它们是否为空

if(a !=null)
{
    foreach (MyType myA in a)
    {
       //DO STUFF HERE
    }
}

无需在
foreach
表达式之前检查计数。如果它是空的,那么它基本上跳过了循环。

问题在于您假设
a
b
从来都不是
null
。如果输入不是json,或者在结构上与您的类型的定义有很大差异,那么这些引用将为null,然后当您尝试在null上迭代时,您将崩溃


如果(a!=null)//iterate
对于每个集合,您只需要执行
if(a!=null)//iterate
,因此,无论何时从
DeserializeObject

分配,您都应该执行空值检查,因为
foreach
将隐式调用
GetEnumerator()
在提供的
IEnumerable
参数上。在
foreach
子句中使用之前,必须为
b
指定一个默认值,或者检查它是否为
null

if ((b != null) && (b.Count > 0)) 
{
    foreach (MyType myB in b)
    {
       //DO STUFF HERE
    }
}

因为我不知道jsonstringa或jsonstringb的值是什么。我猜jsonstringb将是一个空字符串,因为您指的是没有项目的情况。空字符串将被视为格式错误的JSON字符串。结果

JsonConvert.DeserializeObject
当给定一个格式错误的JSON字符串时,它将返回null而不是空列表。这意味着,如果jsonstringb格式不正确或为空字符串,则b为null。这就是为什么每当您请求b.Count或对b执行foreach(foreach将调用b上的GetEnumerator方法)时,都会得到一个null引用异常。因此,您可以执行以下操作:在调用JsonConvert.DeserializeObject之前检查jsonstringb的值,确保它不是空的或null,如果是,则将其设置为空数组

if(string.IsNullOrEmpty(jsonstringb)){
    jsonstringb = "[]";
}
然后打电话

List<MyType> b = JsonConvert.DeserializeObject<List<MyType>>(jsonstringb);
检查集合是否有任何元素的另一种方法是使用any()而不是Count

if(b.Any()){
//you have elements in b
}

myB实际上是null吗?您说过“通过调试,两个集合的Count属性都显示为“0”。你的意思是你将
myB.Count
定义为一个监视表达式,得到了0,但是当你继续执行
时,如果(myB.Count>0)
抛出一个错误?!在上面的代码中,你不是指a.Count而不是myA.Count是列表中的一个吗?或者myA是列表中的一个吗?@JMarsch它显示为空集合,而不是通过调试显示为空集合,尽管根据下面的答案和插入一些检查,它似乎是,这解释了异常,但不是我看到的执行差异。@DadyFuji这正是我看到的,是的。你能解释为什么在这种情况下它会为空吗?当单步调试时,反序列化显示为返回空集合,而不是null,并且“myA”类型似乎就是这种情况,因此缺少异常调用。这似乎允许继续执行,但并不能解释这种异常。我不知道。似乎desialize方法返回null。因为如果集合为空,foreach不会引发异常
if (b!=null){
//Your loop or Count here!
};
if(b.Any()){
//you have elements in b
}