0

I have two Lists that are being populated via JSON deserialization

List<MyType> a = JsonConvert.DeserializeObject<List<MyType>>(jsonstringa);
List<MyType> b = JsonConvert.DeserializeObject<List<MyType>>(jsonstringb);

I then iterate over each one and perform some some logic. It is entirely within reason that these collections may be empty.

foreach (MyType myA in a)
{
   //DO STUFF HERE
}
foreach (MyType myB in b)
{
   //DO STUFF HERE
}

When there are items in the collection for either, there are no problems. However, when there are no items in List B, I get an "Object reference not set to an instance of an object" Exception thrown on the "foreach" line. This, however, does not occur with List A.

I took it a step further and changed the above code just to be safe as well, so that it looks like the following:

if (a.Count > 0)
{
    foreach (MyType myA in a)
    {
       //DO STUFF HERE
    }
}
if (b.Count > 0)
{
    foreach (MyType myB in b)
    {
       //DO STUFF HERE
    }
}

The iteration through the "A" list goes fine whether it's an empty collection or has elements. The iteration through the "B" list again goes fine if there are elements in the collection, but again throws the same exception except this time at the (myB.Count) > 0 line. Through debugging, the Count property for both collections reveal '0' when the collection is empty (as I would expect).

The custom "MyType" class has a default constructor with all non-virtual variables declared as such:

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;
        }
    }
}

I'm a bit at a loss. I have other custom types that are also failing here, but the fact that this pairing of identical types with one getting through just fine and the other throwing the exception is suspect to me and hopefully can help someone give me some insight as to this behavior.

John Saunders
  • 157,405
  • 24
  • 229
  • 388
TheQ
  • 508
  • 5
  • 15
  • is myB in fact, null? – JMarsch Apr 24 '14 at 20:48
  • You said "Through debugging, the Count property for both collections reveal '0'". Do you mean that you defined `myB.Count`as a watch expression and you got 0, but when you continue the execution `if (myB.Count > 0)` throws an error ?! – DadyFuji Apr 24 '14 at 20:52
  • in the above code don't you mean a.Count instead of myA.Count is a the list or is myA the list? – Warrenn enslin Apr 24 '14 at 20:53
  • @JMarsch It's showing as an empty collection as opposed to null through the debug, though based on below answers and plugging in some checks it appears that it is, which explains the Exception but not the difference in execution that I'm seeing. – TheQ Apr 24 '14 at 20:54
  • @DadyFuji That's exactly what I'm seeing, yes. – TheQ Apr 24 '14 at 20:55
  • @Warrennenslin Yes! My mistake. Fixed in edits. – TheQ Apr 24 '14 at 20:55
  • Could you provide the value for jsonstringb and jsonstringa it would stand to reason that jsonstringb is not being parsed correctly? – Warrenn enslin Apr 24 '14 at 21:00
  • Almost all cases of `NullReferenceException` are the same. Please see "[What is a NullReferenceException in .NET?](http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-in-net)" for some hints. – John Saunders Apr 24 '14 at 21:22

5 Answers5

1

If myB is null myB.Count will throw an exception.You should check for null first:

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

You may also want to do that with your first list, for safety...And you can remove the Count check, it's unnecessary.foreach will not throw exception if the collection is empty, it only throws when you try to iterate over a null collection because the foreach calls GetEnumerator method on your collection which is causing to exception.

Selman Genç
  • 94,267
  • 13
  • 106
  • 172
  • Can you explain why it would be null in this case? The deserialization is showing as returning an empty collection as opposed to null when stepping through debugging, and that appears to be the case on the "myA" type, hence the lack of an exception call. That does seem to allow the execution to continue, but it doesn't explain that anomaly. – TheQ Apr 24 '14 at 20:52
  • I don't know.it seems desialize method returns null.because foreach doesn't throw exception if the collection is empty – Selman Genç Apr 24 '14 at 20:57
0

If a or b is null, you can't call functions on it. You'll get a null reference exception. So check to see if they're null.

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

There's no explicit need to check the count before the foreach expression. If it's empty, then it basically skips the loop.

mason
  • 28,517
  • 9
  • 66
  • 106
0

The problem is your assuming that a and b are never null. If the input isn't json or differs to drastically in structure from the definitions for your types those references will be null and then you will crash when you try to iterate on null.

You just need if ( a != null ) // iterate for each of the collections, for that matter you should do a nullity check anytime you assign from DeserializeObject<T>

evanmcdonnal
  • 38,588
  • 13
  • 84
  • 107
0

You cannot iterate on a collection that is null because foreach will implicitly call GetEnumerator() on the supplied IEnumerable argument. You must either assign a default value to b or check that it is not null before using it in the foreach clause.

if ((b != null) && (b.Count > 0)) 
{
    foreach (MyType myB in b)
    {
       //DO STUFF HERE
    }
}
Peter Gluck
  • 7,914
  • 1
  • 36
  • 35
0

As I don't know what the value of jsonstringa or the value of jsonstringb is. I would guess that jsonstringb would be an empty string as you are referring to the case when there are no items. An empty string would be considered a malformed JSON string. The result of

JsonConvert.DeserializeObject

when given a malformed JSON string will return null not an empty list. This means that b is null if jsonstringb is malformed or an empty string. Which is why whenever you ask for b.Count or do a foreach on b (foreach will call the GetEnumerator method on b) you will get a null reference exception. So you can do the following check the value of jsonstringb before calling JsonConvert.DeserializeObject make sure it's not empty or null if so make it an empty array.

if(string.IsNullOrEmpty(jsonstringb)){
    jsonstringb = "[]";
}

then call

List<MyType> b = JsonConvert.DeserializeObject<List<MyType>>(jsonstringb);

and don't forget to do a check for null before you do a loop or call methods on the list.

if (b!=null){
//Your loop or Count here!
};

Another way to check if a collection has any elements would be to use Any() instead of Count.

if(b.Any()){
//you have elements in b
}
Warrenn enslin
  • 976
  • 7
  • 11