'?' in middle of LINQ statement - c#

I cam across this line while going through some not that old code and don't understand why anyone would ever do it:
return dbStudents.MethodToReturnAllStudents()?.Select(x => new dtoStudent(x));
MethodToReturnAllStudents returns an IEnumerable<SQLDomain.Student> (dtoStudent) is in a different namespace -- all the SQLDomain.Student has been mapped from an IDataRecord.
Why would there be a ? in the middle of this statement. Will the LINQ Select try to do anything if MethodToReturnAllStudents returns null?
Is this just terrible code all around?
Side note: Either way, I am refactoring it to follow some alternative standards and to be much more readable.

This is not "old code", since this is a C#6 feature, the Null Conditional Operator. When used, it checks if the immediately preceding value is null before allowing property/method usage on that instance. If it is null, it returns null.
In this scenario, you can translate this code to:
var students = dbStudents.MethodToReturnAllStudents();
if (students == null) return null;
return students.Select(x => new dtoStudent(x));
However, there is actually a larger potential issue with this code than the unfamiliar operator.
The general consensus is that IEnumerable<T> should never return null and, as such, should never need to be null checked. It should always return a sequence that is either hydrated or empty.
That said, if this were in fact List<T> (or a null IEnumerable, although less common), this could be a real scenario (although I would still advocate for never returning null but rather an empty list).
You will have to decide as a development team if the Null Conditional Operator is more succinct and readable. Personally, I'm a fan of it, just not in this context since it is indicative of a larger design smell.

It's not "terrible" code, but it's non-intuitive if you're not familiar with the syntax. I personally enjoy the less-verbose options. LINQ will stop if MethodToReturnAllStudents() returns null and just return that null. It's basically saying
var retVal = dbstudents.MethodToReturnAllStudents();
if(retVal == null) {
return retVal;
} else {
return retVal.Select(x => new dtoStudent(x));
}
Now as users have pointed out, it shouldn't return null as the caller is expecting an IEnumerable.
var retVal = dbstudents.MethodToReturnAllStudents();
if(retVal == null) {
return new List<student>();
} else {
return retVal.Select(x => new dtoStudent(x));
}
Using a null coalescing operator makes the code even more concise and still properly handles return types so it doesn't return null:
return dbStudents.MethodToReturnAllStudents()?.Select(x => new dtoStudent(x)) ?? new List<student>();

It is the Null Conditional Operator
MSDN Documentation
If dbStudents.MethodToReturnAllStudents() is null, it will return null instead of executing .Select(x => new dtoStudent(x)) which would result in a NullReferenceException.

Related

Nullable record structs in C# [duplicate]

So I've got a collection of structs (it's actually a WCF datacontract but I'm presuming this has no bearing here).
List<OptionalExtra> OptionalExtras;
OptionalExtra is a struct.
public partial struct OptionalExtra
Now I'm running the below statement:
OptionalExtra multiOptExtra = OptionalExtras.Where(w => w.Code == optExtra.Code).FirstOrDefault();
if (multiOptExtra != null)
{
}
Now this won't compile:
the operator != cannot be applied to opperands of type OptionalExtra
and '<null>'
After a little googling I realised it's because OptionalExtra is a struct. Which I believe is not nullable unless defined as a nullable type?
So my question is, if my where statement returns no results what will be the outcome of the FirstOrDefault call? Will it thrown an exception?
Incidently this should never happen but better safe than sorry.
If your collection is empty, FirstOrDefault will return default(OptionalExtras). The default value of a struct is the struct with all its values in turn default initialized (i.e. zero, null, etc.).
If you assume that there will be an element and your code doesn't work with an empty collection, Use First() instead, since that will throw an exception when your collection is empty. It's generally better to fail fast than to return wrong data.
If you cannot assume that there will be an element, but also cannot deal with struct default initialization, you might make the structs in the collection a nullable value type, for example as follows:
OptionalExtras
.Where(w => w.Code == optExtra.Code)
.Cast<OptionalExtra?>()
.FirstOrDefault();
This way you can get a null return even for a struct. The key idea here is to extend the set of possible values to include something other than an OptionalExtra to allow detection of an empty list. If you don't like nullables, you could instead use a Maybe<> implementation (not a .NET builtin), or use an empty-or-singleton list (e.g. .Take(1).ToArray(). However, a nullable struct is likely your best bet.
TL;DR;
.FirstOrDefault<T>() returns default(T) if the sequence is empty
Use .First() instead if you assume the list is non-empty.
Cast to nullable and then use .FirstOrDefault<T>() when you cannot assume the list is non-empty.
As others have said, the result of your code when no elements match will be:
default( OptionalExtra )
If you want a null returned, you can cast your list to OptionalExtra?
OptionalExtra? multiOptExtra = OptionalExtras.Cast<OptionalExtra?>().Where( ...
You can then test for null
If default(OptionExtra) is still a valid value, it's better to change your code to this
var results = OptionalExtras.Where(w => w.Code == optExtra.Code).Take(1).ToList();
if (results.Any()) {
multiOptExtra = results[0]
}
The result will be the default value of your struct, e.g. default(OptionalExtras).
Whereas for a reference type the default value is null.
its provide you defualt value for your structure like as below
int[] numbers = { };
int first = numbers.FirstOrDefault();
Console.WriteLine(first);//this print 0 as output
other option to handle is make use of default value like as below
List<int> months = new List<int> { };
// Setting the default value to 1 by using DefaultIfEmpty() in the query.
int firstMonth2 = months.DefaultIfEmpty(1).First();
Console.WriteLine("The value of the firstMonth2 variable is {0}", firstMonth2);
If you want to check for null, use System.Nullable collection:
var OptionalExtras = new List<OptionalExtra?>();
/* Add some values */
var extras = OptionalExtras.FirstOrDefault(oe => oe.Value.Code == "code");
if (extras != null)
{
Console.WriteLine(extras.Value.Code);
}
Note that you have to use Value to access the element.
Assuming Code is a string for the purposes of my answer, you should be able just to test that value for its default.
OptionalExtra multiOptExtra = OptionalExtras.Where(w => w.Code == optExtra.Code).FirstOrDefault();
if (multiOptExtra.Code != null)
{
}

Assignment of property if not null, possible with null-coalecing?

I'm trying to do smth like
Im trying to assign property on an object if this object is not null.
but standard form of non-null invocation does not work for assignment like this
socket?.Blocking = false
what I'm trying to do is shorten this if possible:
if(socket != null) socket.Blocking = false
This would be a great feature
b?.c = "bob"
Though, it's flawed when it comes to compound assignments. Consider this
a.b?.c = "bob"
What should it do on null?
Personally, I think it should just ignore the parents. But alas, the powers that be have probably made the right decision to disallow this because of inconsistency with the other use cases of null conditional.
Note : you could roll your own an extension method, though it's not very satisfying, and would probably fail my code reviews just on abstractness and readability.
a?b.NullConditional(x => x.c = "bob");
You are left with
if(a?.b != null) a.b.c = "bob"
or in your case
if(socket != null) socket.Blocking = false
or to write a dedicated extension method for this use case.
I think the only way would be to use an extension method, so you could write:
socket?.SetBlocking(false);
You can create the extension method like this:
public static class SocketExtensions
{
public static void SetBlocking(this Socket socket, bool blocking)
{
if (socket != null) socket.Blocking = blocking;
}
}

Safely combine two ILists, accounting for nulls

I want to combine two IList's into one, either of which, or both, could be null. If both are null I want the result to be null.
I have this but I want something more elegant but still easy to read.
private IList<Filter> CombineFilters(IList<Filter> first, IList<Filter> second)
{
IList<Filter> result = null;
if(first != null)
if (second != null)
result = first.Concat(second) as IList<Filter>;
else
result = first;
else if (second != null)
result = second;
return result;
}
I would think it’s a bit of a weird behavior if I call your CombineFilters with two lists (one possibly null) and get back a list which is not a copy. That would result in the following behavior:
List<Filter> filters1 = new List<Filter>() { new Filter() };
List<Filter> filters2 = null;
Console.WriteLine(filters1.Count); // 1
var filters = CombineFilters(filters1, filters2);
filters.Add(new Filter());
Console.WriteLine(filters.Count); // 2
Console.WriteLine(filters1.Count); // also 2
I’m not sure if I would really expect this behavior.
So I would suggest you to always ensure that there will be a new list in the end. This allows you to make this really short:
private IList<Filter> CombineFilters(IList<Filter> first, IList<Filter> second)
{
return (first ?? Array.Empty<Filter>()).Concat(second ?? Array.Empty<Filter>()).ToList();
}
Use Enumerable.Concate together with the ?? operator:
if(first == null && second == null)
return null;
return Enumerable.Concat(first ?? Enumerable.Empty<IFilter>(),
second ?? Enumerable.Empty<IFilter>()).ToList();
If either first or second are null a new list will be used instead for the concat.
I think that in case both lists are null then still an initialize collection should be returned. In that case just remove the if statement. Also maybe return an IEnumerable instead of IList:
private IEnumerable<Filter> CombineFilters(IEnumerable<Filter> first, IEnumerable<Filter> second)
{
return Enumerable.Concat(first ?? Enumerable.Empty<IFilter>(),
second ?? Enumerable.Empty<IFilter>());
}
Returning the IEnumerable instead of the IList depends on your scenario. Read more here:
Should I always return IEnumerable<T> instead of IList<T>?
Should I return an IEnumerable or IList?
private IList<Filter> CombineFilters(IList<Filter> first, IList<Filter> second)
{
if (first == null && second == null) return null;
first = first ?? new List<Filter>();
second = second ?? new List<Filter>();
return first.Concat(second).ToList();
}
You could do something like this:
private IList<Filter> CombineFilters(IList<Filter> first, IList<Filter> second)
{
if (first == null && second == null)
{
return null;
}
return (first ?? Enumerable.Empty<Filter>())
.Concat(second ?? Enumerable.Empty<Filter>())
.ToList();
}
That said, it's a good practice to avoid null collections entirely; if there are no elements, you just return an empty collection. This way, you don't need to check for null all the time. This may not be possible to do in your case, but if it is, it will make your code quite a bit cleaner.
Also, consider using IEnumerable<T> rather then IList<T> as it is a more general abstraction (and also because IList<T> is a broken, leaky abstraction - implementations throw exceptions (!) for methods they don't support). On the other hand, I can see that this is a private method, and if you are actually always passing List<Filter>, it's probably better to declare the parameters as List<Filter>.
EDIT:
Just noticed my answer is very similar to the one posted by Gilad Green, which I didn't see before.

How to read such construction?

I've jumped into such a thing in my code and I don't really know how to read this. Would be nice if somebody could help me with this :)
return Company?.Call?.SingleOrDefault(cf => cf.Name == Client?.CallID)
?? Company?.Call?.SingleOrDefault(cf => cf.IsDefault)
?? new CallData();
The ?. operator is called a Null-conditional operator and is a new feature from C# 6, and was announced in October 2014. https://msdn.microsoft.com/en-us/library/dn986595.aspx
The first part: Company?.Call?.SingleOrDefault can be seen as similar to this:
if (Company == null)
{
return null;
}
else if (Company.Call == null)
{
return null;
}
else
{
return Company.Call.SingleOrDefault(....
}
But then the original coder uses the ?? Null-coalesce operator, which has been a part of C# since at least 2007. It means that if whatever is left of the ?? is null, evaluate what is right of the ?? and return that instead.
So the code basically means:
If Company is null, return new CallData()
If Company.Call is null, return new CallData()
If the first call to Company.Call.SingleOrDefault returns a CallData instance (having a certain value for the Name property) , return that instance
If the first call returns null, but the second call returns a CallData instance (being the default one) , return that instance
If both calls to SingleOrDefault return null, return new CallData()
This piece of code has some issues.
First of all, it is unreadable and should be refactored into something that is easier to understand. New language features are nice, but only when used responsibly.
Second: If there are more than one CallData instances with the same Name, the SingleOrDefault will throw an exception, but there might be a unique index in the database the prevents this. The same goes for IsDefault property - if there are more than one records with IsDefault = true, the SingleOrDefault call will throw an exception.
Split it to 3 expressions first, separated by the ??:
Company?.Call?.SingleOrDefault(cf => cf.Name == Client?.CallID)
??
Company?.Call?.SingleOrDefault(cf=>cf.IsDefault)
??
new CallData();
The returned value of the entire expression would be the first expression that is returning a non-null value.
Within each segment, once any of the properties accessed using ?. is null, the entire expression will be evaluated to null.
See Null-conditional Operators

Null conditional operator to "nullify" array element existence

The new C# 6.0 null-conditional operator is a handy vehicle for writing more concise and less convoluted code. Assuming one has an array of customers, then you could get null instead of a length if customers is null using this (examples from MSDN):
int? length = customers?.Length;
Similarly you could get null instead of a customer with this:
Customer first = customers?[0];
And for a more elaborate expression, this yields null if customers is null, the first customer is null, or the first customer's Orders object is null:
int? count = customers?[0]?.Orders?.Count();
But then there is the interesting case of the non-existent customer that the null-conditional operator does not seem to address. We saw above that a null customer is covered, i.e. if an entry in the customers array is null. But that is quite distinct from a non-existent customer, e.g. looking for customer 5 in a 3-element array or customer n in a 0-element list. (Note that the same discussion applies to Dictionary lookup as well.)
It seems to me that the null-conditional operator is focused exclusively on negating the effects of a NullReferenceException; IndexOutOfRangeException or KeyNotFoundException are alone, exposed, cowering in the corner, and needing to fend for themselves! I submit, that in the spirit of the null-conditional operator, it should be able to handle those cases as well... which leads to my question.
Did I miss it? Does the null-conditional provide any elegant way to truly cover this expression...
customers?[0]?.Orders?.Count();
...when there is no zeroth element?
No, because it is a null-conditional operator, not an indexoutofrange-conditional operator and is merely syntactic sugar to something like the following:
int? count = customers?[0]?.Orders?.Count();
if (customers != null && customers[0] != null && customers[0].Orders != null)
{
int count = customers[0].Orders.Count();
}
You can see that if there is no zeroth customer, you will get your regular IndexOutOfRangeException.
One way you could work around it is to have an extension method that checks for the index and returns null if it doesn't exist:
public static Customer? GetCustomer(this List<Customer> customers, int index)
{
return customers.ElementAtOrDefault(index); // using System.Linq
}
Then your check could be:
int? count = customers?.GetCustomer(0)?.Orders?.Count();
customers?.FirstOrDefault()?.Orders?.Count();
No zeroeth, no problem.
If you want to get the nth element without having NullReference or IndexOutOfRange exceptions, you can use:
customers?.Skip(n)?.FirstOrDefault()
It doesn't support indexing safety because, when you get down to it, an indexer really is just syntactic sugar for any other type of method.
For example:
public class MyBadArray
{
public Customer this[int a]
{
get
{
throw new OutOfMemoryException();
}
}
}
var customers = new MyBadArray();
int? count = customers?[5]?.Orders?.Count();
Should this be caught here? What if the exception was more sensible, similar to a KeyNotFoundException, but specific to the type of collection we're implementing? We'd have to continually update the ?. functionality to keep up.
Further, ?. does not catch exceptions. It prevents them.
var customer = customers?[5]; is actually compiled as:
Customer customer = null;
if (customers != null)
customer = customers[5];
Making it catch exceptions becomes exceptionally more difficult. For example:
void Main()
{
var thing = new MyBadThing();
thing.GetBoss()?.FireSomeone();
}
public class MyBadThing
{
public class Boss
{
public void FireSomeone()
{
throw new NullReferenceException();
}
}
public Boss GetBoss()
{
return new Boss();
}
}
If it were simply catching exceptions, it would be written as :
Boss boss = customer.GetBoss();
try
{
boss.FireSomeone();
} catch (NullReferenceException ex) {
}
Which would actually catch the exception within FireSomeone, rather than the null reference exception which would be thrown if boss were null.
The same bad-catching problem would be present if we were to catch index lookup exceptions, key not found exceptions, etc.

Categories

Resources