How to deal with null linq query result? - c#

I have a linq query in which i am getting the user list and after that we are getting the record by userid filter.
var user = UserDal.GetAllUsers().First(n => n.UsersID == 1);
But what should do if GetAllUsers() function returns null ? Should we check it by applying Any() ? Or something else ?

But what should do if GetAllUsers() function returns null ?
If UserDal.GetAllUsers returns null, then you can't use Any, you will have to check it against null. You can only use Any or FirstOrDefault if the method returns a collection (even empty).
If the method could return null then:
var temp = UserDal.GetAllUsers();
if(temp != null)
{
var user = temp.FirstOrDefault(n=> n.UserID == 1);
}
If your method could return an empty collection instead of null then you can do:
var user = UserDal.GetAllUsers().FirstOrDefault(n => n.UsersID == 1);
You should modify your method UserDal.GetAllUsers to not return a null. If there are no records then an empty collection should be returned.

Why not simply check if it is null?
var users = UserDal.GetAllUsers();
if (users == null || !users.Any())
{
// handle error
}
var user = users.First(x => x.Id == someId);
However, if you're in control of the code-base, I'd certainly say that you should make it so GetAllUsers never returns null.

You could use [DefaultIfEmpty] and use that instance as default value: to handle null value

You could use Monads, e.g. https://github.com/sergun/monads.net
Or you could implement your own extension methods.
This code is adapted from the original extension method and returns default(T) instead of throwing an exception.
// UserDal.GetAllUsers() returns null and user is null
var user = UserDal.GetAllUsers().MyFirstOrDefault(n => n.UsersID == 1);
public static class IEnumerableExtensions
{
public static T MyFirstOrDefault<T>(this IEnumerable<T> source,
Func<T, bool> predicate)
{
if (source == null) return default(T);
if (predicate == null) return default(T);
foreach (T element in source)
{
if (predicate(element)) return element;
}
return default(T);
}
}
Or you could use null checks or ensure never to return null to safeguard against null reference exception when using the standard extension methods.

Related

LINQ ternary result of binary list

Assume I have a list of binary parameters (in reality it is a list of checkboxes' IsChecked.Value property). I'm trying to get the bool? (ternary) result that:
is true if all the elements in the list are true
is false if all the elements in the list are false
is null in all other cases, thus there are both true and false elements in the list or the list is empty
Until now I came up with the solution that requires iterating over the list twice (checking whether all elements are either true or false) and then comparing the results to deciding whether to return true, false or null.
This is my code:
bool checkTrue = myListOfBooleans.All(l => l);
bool checkFalse = myListOfBooleans.All(l => !l);
bool? result = (!checkTrue && !checkFalse) ? null : (bool?)checkTrue;
How can I achieve it in only one iteration over the list?
You could do that by using Aggegrate
public bool? AllSameValue(List<bool> myListOfBooleans)
{
if(myListOfBooleans.Count == 0) return null; // or whatever value makes sense
return myListOfBooleans.Cast<bool?>().Aggregate((c, a) => c == a ? a : null);
}
That casts your values to bool? so that you can then compare them and return the value if that they all match or null if there is a difference.
Of course you could exit early by taking the first one and using All to see if the rest match or not.
public bool? AllSameValue(List<bool> myListOfBooleans)
{
if(myListOfBooleans.Count == 0) return null; // or whatever value makes sense
bool first = myListOfBooleans[0];
return myListOfBooleans.All(x => x == first ) ? first : null;
}
You can simply count the true values:
int c = myListOfBooleans.Count(l => l);
bool? result = c == myListOfBooleans.Count
? (bool?)true
: (c == 0 ? (bool?)false : null);
Note that this is true for an empty list, you may want to tweak that according to your required logic.
For a better performance (though I don't think it matters in a UI context) you could write an extension that could even return early if the result is clear (instead of iterating through the whole list):
public static bool? AllOrNothing(this IEnumerable<bool> list)
{
if (list == null) throw new ArgumentNullException(nameof(list));
using(var enumerator = list.GetEnumerator())
{
if (!enumerator.MoveNext())
return null; // or true or false, what you need for an empty list
bool? current = enumerator.Current;
while(enumerator.MoveNext())
if (current != enumerator.Current) return null;
return current;
}
}
And use it:
bool? result = myListOfBooleans.AllOrNothing();

Null reference exception after checking for null (checking for null doesn't work)

Take a look at this code:
var categories = tokens.SelectMany(x => x.Categories);
if (categories != null)
{
if (categories.Contains("interp")) //null ref exception
{
return null;
}
}
I get Null Reference Exception when I try fo find "interp" string within categories. So it seems that "categories != null" doesn't work.
I found some suggestions (here How to check if IEnumerable is null or empty?) but they involve using .Any(). But it only makes the exception accure earlier (while using .Any()). Even ?.Any() throws the exception.
Any ideas?
This code will throw an NRE in categories.Contains only if the Categories property is null.
The following code will throw :
class Token
{
public string[] Categories{get;set;}
}
var tokens=new []{new Token()};
var categories = tokens.SelectMany(x => x.Categories);
if (categories != null)
{
if (categories.Contains("interp"))
{
Console.WriteLine("Found");
}
}
But so would
tokens.SelectMany(x => x.Categories).ToArray();
The thing that actually throws is the nested iterator inside SelectMany, not ToArray() or Contains. The stack trace for that exception is :
at System.Linq.Enumerable.<SelectManyIterator>d__17`2.MoveNext()
at System.Linq.Enumerable.Contains[TSource](IEnumerable`1 source, TSource value, IEqualityComparer`1 comparer)
at UserQuery.Main()
SelectMany will try to iterate over each Categories entry, find that the property is actually null and throw.
The quick fix is to add a Where before SelectMany to eliminate null Categories :
var categories = tokens.Where(x=>x.Categories!=null).SelectMany(x => x.Categories);
The real solution is to ensure Categories is never empty - it should be initialized to an empty array, list, whatever upon construction. When reassigned, it should never be set to null.
This example sets the _categories field to new string[0] even if a caller passes null to Categories
class Token
{
string[] _categories=new string[0];
public string[] Categories{
get => _categories;
set => _categories = value??new string[0];
}
}
With that, Where(x=>x.Categories !=null) is no longer necessary
When working with collections and IEnumerable<T> avoid using null; if you have nothing to return, return an empty collection (not null).
In your particular case SelectMany will never return null, but empty collection, that's why categories != null check is useless,
and you have to check tokens instead
if (null != tokens)
// Where(x => x != null) - to be on the safe side if x == null or x.Categories == null
if (tokens
.Where(x => x != null && x.Categories != null)
.SelectMany(x => x.Categories)
.Contains("interp"))
return null;
However, constant checking for null makes code being unreadable, that's why try check for null once:
// if tokens is null change it for an empty collection
tokens = tokens ?? new MyToken[0];
...
if (tokens
.Where(x => x != null && x.Categories != null)
.SelectMany(x => x.Categories)
.Contains("interp"))
return null;
var categories = tokens.SelectMany(x => x.Categories).ToList();
add .ToList() and you should know more about where the error is
with that information we have in the post, we can only guess
Can use where clause and make it as list , then just check if there is any element in the list
var categories = list.Where(x => x.Categories.Contains("interp")).ToList();
if (categories.Count() == 0)
{
return null;
}

Linq Query Crash if Return Null

I run this query And if The Query is return with empty values the programme is crashed.
var cust = db.Customers.FirstOrDefault(x => x.telephone == txtTel.Text);
if (cust.BlackList == 1)
{
MessageBox.Show("This customer is blacklisted, Do you wish to continue with this job?");
}
Please Suggest me Some Efficient solution
Thanks.
You are getting a null pointer because FirstOrDefault returns the default value of the object if the result is not found (in this case it is null):
var cust = db.Customers.FirstOrDefault(x => x.telephone == txtTel.Text);
if (cust != null && cust.BlackList == 1)
{
MessageBox.Show("This customer is blacklisted, Do you wish to continue with this job?");
}
You need to check for null because that's what FirstOrDefault returns if there is no record that satisfies your condition:
if(cust != null && cust.BlackList == 1)
FirstOrDefault will return a default value if there is no element in the list which satisfy the condition, in this case it will be null. As you call a property on the null value it will naturally cause an exception.
You should check if cust is null, like:
if(cust != null && cust.BlackList == 1)
Of course you can display another message if the user doesn't exist based on the logic of your application.

Handling Nulls in a model passed over into a controller

I am trying to fix these linq statements so that they wont error if the model is null.
For example:
model.FilterSet.Dispositions may be null. While model.FilterSet.GenderFilters may not.
My current linq statement gives error if there is a null so I tried to add .Where(item => item != null) in the DispositionFilters linq, but it gives me an error saying that this will always be true.
Here is my code:
var filters = new RespondentCSVFilters
{
CSVFilters = new CSVFilters
{
DispositionFilters = model.FilterSet.Dispositions.Where(item=>item != null).ToList().ConvertAll(item => (int)((RespondentStatus)Enum.Parse(typeof(RespondentStatus), item.ToString()))),
EthnicitiesFilters = model.FilterSet.Ethnicities.ConvertAll(item => (int)((Ethnicity)Enum.Parse(typeof(Ethnicity), item.ToString()))),
GenderFilters = model.FilterSet.Genders.ConvertAll(item => (int)((Gender)Enum.Parse(typeof(Gender), item.ToString()))),
SourcesFilters = model.FilterSet.Sources.ConvertAll(item => (int)((RespondentSource)Enum.Parse(typeof(RespondentSource), item.ToString()))),
}
};
I am not sure how to make the changes in order to handle nulls.
I tried to add .Where(item => item != null)
But this will only check each item for null, not the source ("Dispositions"). To check for null fluently (without adding a bunch of "if" statements), an EmptyIfNull extension can be helpful:
public static class Extensions
{
public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> self)
{
return self == null ? Enumerable.Empty<T>() : self;
}
}
Now you can write ...
model.FilterSet.Dispositions.EmptyIfNull().Where( ... )
and if model.FilterSet.Dispositions is null, you won't get an exception, but the statement will evaluate to an empty set.

Exception in IEnumerable when it's null

I have a method returning IEnumerable object, but I found that sometimes (on error) the method returns null value of IEnumerable.
The method looks something like this.
IEnumerable<string> function(String param1, String param2)
{
IEnumerable s = null;
s = (some query over here);
return s;
}
When I call this method with param2, the function internally fails and returns s which is null at this time.
So, to detect this I used,
IEnumerable<string> a = function(1,0);
if (a.count<string> > 0) //not working
if (a == 0) //not working.
What is the correct method to use IEnumerable and check whether it is null before any other operation?
you could return an empty enumerable if the search result was null:
IEnumerable<string> function(String param1, String param2)
{
IEnumerable s = null;
s = (some query over here);
return s ?? Enumerable.Empty<string>();
}
Yours s = (some query over here); is returning null. That is why you are getting the exception.
Later your check should be:
if(a != null)
and
if(a.Count() > 0)
You can combine both as:
if(a!=null && a.Count() >0)
{
// do your work
}
null is not the same as an enumeration without any elements. Therefore, your check for if(a.count<string> > 0) fails. (In fact, a isn't pointing to any instance whose number of elements you could retrieve with Count.)
Also, null is not the same as the integer value 0. Therefore, your check for if(a == 0) fails, too.
However, null is a keyword in C# and you can compare to that:
if (a == null)

Categories