0

I want to test if my byte[] element ImageData contains any data. If there is no data my database shows it as NULL. I tried using the .Any() method, but for some reason this does not work. Why?

I have tried it with the following code

public FileStreamResult ViewImage(int id)
{
    Candidate candidate = _context.Candidate.FirstOrDefault(m => m.Id == id);
    bool hasImage = candidate.ImageData.Any();  // I get the NullException here          

    if (hasImage)
    {
        MemoryStream ms = new MemoryStream(candidate.ImageData);
        return new FileStreamResult(ms, candidate.ImageType);
    }
    return null;            
}

If I use the logic if(candidate.ImageData == null), I get a true or false. I considered using Any() more elegant. Any suggestions?

Backs
  • 24,430
  • 5
  • 58
  • 85
Charles de M.
  • 633
  • 7
  • 20
  • 2
    Does this answer your question? [What is a NullReferenceException, and how do I fix it?](https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – derpirscher Mar 23 '21 at 11:06
  • @derpirscher : it does with addition of John Skeet below – Charles de M. Mar 23 '21 at 11:08

3 Answers3

2

It doesn't work because you're calling a method on a null reference... In this case it's an extension method so you'll get an ArgumentNullException instead of a NullReferenceException, but it's behaving exactly as documented.

You can write your own extension method for this if you want:

public class NullSafeEnumerable
{
    public static bool NonNullAny<T>(this IEnumerable<T> source) =>
        source is object && source.Any();
}

(That's not a great name, but you can come up with your own one.)

Or you could use the null-conditional operator:

bool hasImage = candidate.ImageData?.Any() ?? false;

or (equivalently):

bool hasImage = candidate.ImageData?.Any() == true;
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks for the clarification. It is a bit baffling. The object should exist, but the contents may be null? In my case the object did not exist. That is the logic what I've learned. – Charles de M. Mar 23 '21 at 11:00
  • @CharlesdeM.: It's not clear which object you're talking about - it sounds like the object referred to by the `candidate` variable, but that its `ImageData` returned a null reference rather than a reference to a byte array. That seems entirely reasonable if the value is NULL in the database. Note that a byte array object can't have "null contents", although it can be an array of length 0. – Jon Skeet Mar 23 '21 at 11:04
2

You have to check for the NULL before calling the .Any(), so it won't throw the NullPointerException.

In trival methods you can use

bool hasImage = candidate.ImageData != null && candidate.ImageData.Any(); 

In the new way you can use the Null Conditional operator C# like

bool hasImage = candidate?.ImageData?.Any() == true; 

,which keeps elegant as you wish.

Other way, you can use the Jon's method of null-coalescing operator.

EDIT: As suggested by Jon Skeet, changing the wrong operator name and correcting the last option to de-reference the bool? value.

Sathish Guru V
  • 1,417
  • 2
  • 15
  • 39
  • That last approach won't compile, because the expression `candidate?.ImageData?.Any()` has a type of `bool?`, not `bool` - hence the `?? false` in my answer. – Jon Skeet Mar 23 '21 at 11:04
  • Thanks Sathish for the insight in the `coalescing operator c#`. Very helpful. – Charles de M. Mar 23 '21 at 11:05
  • That's not the null-coalescing operator though - it's the null-conditional operator. (It's definitely worth knowing about both :) – Jon Skeet Mar 23 '21 at 11:07
0

You can also use C# 6.0 feature called Null-conditional operator

bool hasImage = candidate?.ImageData?.Any() == true;

If any of the objects before .Any() is null then the entire expression will return null.

Grzegorz Pasnik
  • 164
  • 2
  • 7