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
Related
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)
{
}
I have an object where a property may exist or may not exist.
if(response.AddressInformation.AddressResponses.Any(inf => inf.AddressResponse.matchCodeStatus.ToLower().Equals("usps_match")))
{
}
I have two array items of AddressResponse. First item has null for matchCodeStatus and thats where I get object not set to an instance exception. How can I achieve my target and escape this exception?
I tried to put a null check before my IF, but it didnt work
if(response.AddressInformation.AddressResponses.Any(inf => inf.AddressResponse.matchCodeStatus != null)
As of C# 6, you can also use a null conditional operator ?. :
inf => inf.AddressResponse.matchCodeStatus?.ToLower().Equals("usps_match"))
I have just installed ReSharper, and it has altered
if(dto != null)
{
return new test{
obj1 = "",
obj2 = "",
}
}
into
return dto?.Select(item => new test
{
return new test{
obj1 = "",
obj2 = "",
}
I have not seen before
dto?.Select
tried to google the meaning with no luck.. could someone please explain , or point me in the right direction to the deffination
I gather its simply checking for null?
Null propagation operator is newly introduced in C# 6. return dto?.Select... means, if dto is null then this statement will return null else will execute the remaining part.
Another example, just making it up, assume you have Employee object with Address property which inturn has Lane (string), Pincode etc.
So if you need to get the address lane value you could do:
var lane = employee?.Address?.Lane;
Which will return null if employee or address is null; otherwise returns lane value.
This could be combined in many ways and is really handy.
For eg,
int someIntegerValue = someObject?.SomeIntValue ?? 0;
Basically you could avoid many null checks with this feature.
The question-mark operator acts on nullable values and
x?<operation>
translates to
x.HasValue ? x.Value.<operation> : null
It's basically saying "do this if I'm not null; otherwise keep me as null".
Do you have a
return null
statement later in your original code? I am surprised ReSharper would assume a return null in its transformation.
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.
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.