Possible pitfalls of using this (extension method based) shorthand - c#

C#6 Update
In C#6 ?. is now a language feature:
// C#1-5
propertyValue1 = myObject != null ? myObject.StringProperty : null;
// C#6
propertyValue1 = myObject?.StringProperty;
The question below still applies to older versions, but if developing a new application using the new ?. operator is far better practice.
Original Question:
I regularly want to access properties on possibly null objects:
string propertyValue1 = null;
if( myObject1 != null )
propertyValue1 = myObject1.StringProperty;
int propertyValue2 = 0;
if( myObject2 != null )
propertyValue2 = myObject2.IntProperty;
And so on...
I use this so often that I have a snippet for it.
You can shorten this to some extent with an inline if:
propertyValue1 = myObject != null ? myObject.StringProperty : null;
However this is a little clunky, especially if setting lots of properties or if more than one level can be null, for instance:
propertyValue1 = myObject != null ?
(myObject.ObjectProp != null ? myObject.ObjectProp.StringProperty) : null : null;
What I really want is ?? style syntax, which works great for directly null types:
int? i = SomeFunctionWhichMightReturnNull();
propertyValue2 = i ?? 0;
So I came up with the following:
public static TResult IfNotNull<T, TResult>( this T input, Func<T, TResult> action, TResult valueIfNull )
where T : class
{
if ( input != null ) return action( input );
else return valueIfNull;
}
//lets us have a null default if the type is nullable
public static TResult IfNotNull<T, TResult>( this T input, Func<T, TResult> action )
where T : class
where TResult : class
{ return input.IfNotNull( action, null ); }
This lets me us this syntax:
propertyValue1 = myObject1.IfNotNull( x => x.StringProperty );
propertyValue2 = myObject2.IfNotNull( x => x.IntProperty, 0);
//or one with multiple levels
propertyValue1 = myObject.IfNotNull(
o => o.ObjectProp.IfNotNull( p => p.StringProperty ) );
This simplifies these calls, but I'm not sure about checking this sort of extension method in - it does make the code a little easier to read, but at the cost of extending object. This would appear on everything, although I could put it in a specifically referenced namespace.
This example is a rather simple one, a slightly more complex one would be comparing two nullable object properties:
if( ( obj1 == null && obj2 == null ) ||
( obj1 != null && obj2 != null && obj1.Property == obj2.Property ) )
...
//becomes
if( obj1.NullCompare( obj2, (x,y) => x.Property == y.Property )
...
What are the pitfalls of using extensions in this way? Are other coders likely to be confused? Is this just abuse of extensions?
I guess what I really want here is a compiler/language extension:
propertyValue1 = myObject != null ? myObject.StringProperty : null;
//becomes
propertyValue1 = myObject?StringProperty;
This would make the complex case far easier:
propertyValue1 = myObject != null ?
(myObject.ObjectProp != null ? myObject.ObjectProp.StringProperty) : null
//becomes
propertyValue1 = myObject?ObjectProp?StringProperty;
This would only work for value types, but you could return nullable equivalents:
int? propertyValue2 = myObject?ObjectProp?IntProperty;
//or
int propertyValue3 = myObject?ObjectProp?IntProperty ?? 0;

We independently came up with the exact same extension method name and implementation: Null-propagating extension method. So we don't think it's confusing or an abuse of extension methods.
I would write your "multiple levels" example with chaining as follows:
propertyValue1 = myObject.IfNotNull(o => o.ObjectProp).IfNotNull(p => p.StringProperty);
There's a now-closed bug on Microsoft Connect that proposed "?." as a new C# operator that would perform this null propagation. Mads Torgersen (from the C# language team) briefly explained why they won't implement it.

Here's another solution, for chained members, including extension methods:
public static U PropagateNulls<T,U> ( this T obj
,Expression<Func<T,U>> expr)
{ if (obj==null) return default(U);
//uses a stack to reverse Member1(Member2(obj)) to obj.Member1.Member2
var members = new Stack<MemberInfo>();
bool searchingForMembers = true;
Expression currentExpression = expr.Body;
while (searchingForMembers) switch (currentExpression.NodeType)
{ case ExpressionType.Parameter: searchingForMembers = false; break;
case ExpressionType.MemberAccess:
{ var ma= (MemberExpression) currentExpression;
members.Push(ma.Member);
currentExpression = ma.Expression;
} break;
case ExpressionType.Call:
{ var mc = (MethodCallExpression) currentExpression;
members.Push(mc.Method);
//only supports 1-arg static methods and 0-arg instance methods
if ( (mc.Method.IsStatic && mc.Arguments.Count == 1)
|| (mc.Arguments.Count == 0))
{ currentExpression = mc.Method.IsStatic ? mc.Arguments[0]
: mc.Object;
break;
}
throw new NotSupportedException(mc.Method+" is not supported");
}
default: throw new NotSupportedException
(currentExpression.GetType()+" not supported");
}
object currValue = obj;
while(members.Count > 0)
{ var m = members.Pop();
switch(m.MemberType)
{ case MemberTypes.Field:
currValue = ((FieldInfo) m).GetValue(currValue);
break;
case MemberTypes.Method:
var method = (MethodBase) m;
currValue = method.IsStatic
? method.Invoke(null,new[]{currValue})
: method.Invoke(currValue,null);
break;
case MemberTypes.Property:
var method = ((PropertyInfo) m).GetGetMethod(true);
currValue = method.Invoke(currValue,null);
break;
}
if (currValue==null) return default(U);
}
return (U) currValue;
}
Then you can do this where any can be null, or none:
foo.PropagateNulls(x => x.ExtensionMethod().Property.Field.Method());

If you find yourself having to check very often if a reference to an object is null, may be you should be using the Null Object Pattern. In this pattern, instead of using null to deal with the case where you don't have an object, you implement a new class with the same interface but with methods and properties that return adequate default values.

How is
propertyValue1 = myObject.IfNotNull(o => o.ObjectProp.IfNotNull( p => p.StringProperty ) );
easier to read and write than
if(myObject != null && myObject.ObjectProp != null)
propertyValue1 = myObject.ObjectProp.StringProperty;
Jafar Husain posted a sample of using Expression Trees to check for null in a chain, Runtime macros in C# 3.
This obviously has performance implications though. Now if only we had a way to do this at compile time.

I just have to say that I love this hack!
I hadn't realized that extension methods don't imply a null check, but it totally makes sense. As James pointed out, The extension method call itself is not any more expensive than a normal method, however if you are doing a ton of this, then it does make sense to follow the Null Object Pattern, that ljorquera suggested. Or to use a null object and ?? together.
class Class1
{
public static readonly Class1 Empty = new Class1();
.
.
x = (obj1 ?? Class1.Empty).X;

it does make the code a little easier to read, but at the cost of extending object. This would appear on everything,
Note that you are not actually extending anything (except theoretically).
propertyValue2 = myObject2.IfNotNull( x => x.IntProperty, 0);
will generate IL code exactly as if it were written:
ExtentionClass::IfNotNull(myObject2, x => x.IntProperty, 0);
There is no "overhead" added to the objects to support this.

To reader not in the know it looks like you're calling a method on a null reference. If you want this, I'd suggest putting it in a utility class rather than using an extension method:
propertyValue1 = Util.IfNotNull(myObject1, x => x.StringProperty );
propertyValue2 = Util.IfNotNull(myObject2, x => x.IntProperty, 0);
The "Util." grates, but is IMO the lesser syntactic evil.
Also, if you developing this as part of a team, then gently ask what others think and do. Consistency across a codebase for frequently used patterns is important.

While extension methods generally cause misunderstandings when called from null instances, I think the intent is pretty straightforward in this case.
string x = null;
int len = x.IfNotNull(y => y.Length, 0);
I would want to be sure this static method works on Value Types that can be null, such as int?
Edit: compiler says that neither of these are valid:
public void Test()
{
int? x = null;
int a = x.IfNotNull(z => z.Value + 1, 3);
int b = x.IfNotNull(z => z.Value + 1);
}
Other than that, go for it.

Not an answer to the exact question asked, but there is Null-Conditional Operator in C# 6.0. I can argue it will be a poor choice to use the option in OP since C# 6.0 :)
So your expression is simpler,
string propertyValue = myObject?.StringProperty;
In case myObject is null it returns null. In case the property is a value type you have to use equivalent nullable type, like,
int? propertyValue = myObject?.IntProperty;
Or otherwise you can coalesce with null coalescing operator to give a default value in case of null. For eg,
int propertyValue = myObject?.IntProperty ?? 0;
?. is not the only syntax available. For indexed properties you can use ?[..]. For eg,
string propertyValue = myObject?[index]; //returns null in case myObject is null
One surprising behaviour of the ?. operator is that it can intelligently bypass subsequent .Member calls if object happens to be null. One such example is given in the link:
var result = value?.Substring(0, Math.Min(value.Length, length)).PadRight(length);
In this case result is null if value is null and value.Length expression wouldn't result in NullReferenceException.

Personally, even after all your explanation, I can't remember how the heck this works:
if( obj1.NullCompare( obj2, (x,y) => x.Property == y.Property )
This could be because I have no C# experience; however, I could read and understand everything else in your code. I prefer to keep code language agnostic (esp. for trivial things) so that tomorrow, another developer could change it to a whole new language without too much information about the existing language.

Here is another solution using myObject.NullSafe(x=>x.SomeProperty.NullSafe(x=>x.SomeMethod)), explained at
http://www.epitka.blogspot.com/

Related

C# - .Find() Null vs Empty List condition

I have a .Find statement like so:
MyObject obj = existingObjs.Find(x => x.listA == currentObj.listA &&
x.listB == currentObj.listB);
Unfortunately "obj" is always null because my "currentObj" has a listB = null but "x.listB" is always an empty list. I want to treat null and empty list as the same thing, how would I put that into my .Find statement?
I tried something like so but, it is returning a bool instead of an obj so it won't compile.
MyObject obj = existingObjs.Find(x => x.listA == currentObj.listA &&
(x.listB == null ? null : currentObj.listB));
Some points to note:
you should rather not use == for comparing complicated objects like lists, since == tests for reference equality, not the structure (e.g. whether elements on the list are the same). For comparing lists you could use Enumerable.SequenceEqual
mixing null and empty list in the same variable is a bad practice that will hit you in many places just like here, but for handling null vs empty there is nullish coalescing operator x.listB ?? Enumerable.Empty() that will always return enumerable object that you can use for comparisons
all of this should be put into bool Equals(MyObject other) method
for example
using System;
using System.Linq;
class MyObject<T> : IEquatable<MyObject<T>> {
public bool Equals(MyObject<T> other) {
if (other == null)
return false;
return ListsEqual(listA, other.listA) &&
ListsEqual(listB, other.listB);
}
bool ListsEqual(IList<T> l1, IList<T> l2) {
return Enumerable.SequenceEqual(ListOrEmpty(l1), ListOrEmpty(l2));
}
IEnumerable<T> ListOrEmpty(IList<T> li) {
return li ?? Enumerable.Empty<T>();
}
IList<T> listA;
IList<T> listB;
}
You could use the conditional operator:
currentObj.listB == null ?
!Any(x.listB) :
Enumerable.SequenceEqual(currentObj.listB, x.listB)
You could use null-coalescing operator to make sure array in currentObject will be empty arrays when they are null and then compare them:
currentObject.listA ??= Array.Empty<ListAType>();
currentObject.listB ??= Array.Empty<ListBType>();
MyObject obj = existingObjs.Find(x => Enumerable.SequenceEqual(x.listA, currentObj.listA) &&
Enumerable.SequenceEqual(x.listB, currentObj.listB));

Pattern matching equal null vs is null

From Microsoft new-features-in-c-7-0:
public void PrintStars(object o)
{
if (o is null) return; // constant pattern "null"
if (!(o is int i)) return; // type pattern "int i"
WriteLine(new string('*', i));
}
Whats the diferrence of o == null and o is null?
The o is null is translated to object.Equals(null, o) (you can see it here).
The object.Equals code is written as:
public static bool Equals(Object objA, Object objB)
{
if (objA == objB)
{
return true;
}
if (objA == null || objB == null)
{
return false;
}
return objA.Equals(objB);
}
so in the end there will be a o == null (the first if). Note that System.Object doesn't define the operator==, so the one used is the one for reference types that is reference equality.
Theorically, by watching the called code, one could think that o == null (with o a System.Object) should be faster than o is null (less operations)... But who knows? :-)
The end result is that, through two different routes, o is null and o == null (with o a System.Object) return the same result.
By looking we can even see that o == null is the same as object.ReferenceEquals(o, null) (with o a System.Object) :-).
the interesting question should be, why doesn't the C# compiler translates the x is null to object.ReferenceEquals(x, null)?. Note that, thanks to how the boxing of nullable types is done, it would work even for:
int? a = null;
if (a is null) { /* */ }
changes to the compiler made this response invalid... If you click on the "here" link you can see it
Since the answer of #xanatos is outdated (but that is only mentioned at the very end) I'm writing a new one, because I wanted to know this as well and researched it.
In short: if you don't overload the == operator, then o == null and o is null are the same.
If you do overload the == operator, then o == null will call that, but o is null won't.
o is null always does the same as ReferenceEquals(o, null), i.e. it only checks if the value is null, it doesn't call any operators or Equals methods.
Longer answer: here is a SharpLab sample that showcases the various ways to check for null.
If you view the result in IL form you see that:
is null and ReferenceEquals result in the same code
o == null will call the overloaded operator==
object.Eqauls(o, null) calls that method
if you comment the operator== in class C you will see that o == null now produces the same code as o is null
The differences between "is" and == is "is" special that it act as == if you compare to value and act as typeof(type) when you compare type of object to type.

Union collections only if second TSource is not Null

I have the following linq statement:
List<Type> allTypes = group.GetTypes().Union(group2.GetTypes()).ToList();
There might be a case when group2 is null which will throw me NullReferenceException
One way to solve this is to perform null check before, something like:
if (group2 != null)
{
List<Type> allTypes = group.GetTypes().Union(group2.GetTypes()).ToList();
}
else
{
List<Type> allTypes = group.GetTypes();
}
but the problem is that I have many similar assignment for different types and don't want to do if statements for each of them in such a way, but I'd rather put null check in one line, something like:
List<Type> allTypes = group.GetTypes().Union((if group2 != null)group2.GetTypes()).ToList();
but not sure how to do it with linq.
The problem you have here is not TSource being null; it's the object you want to get source from is null (group2).
You can always use Enumerable.Empty to save your magic one liners.
List<Type> allTypes = group.GetTypes().Union(group2 != null ? group2.GetTypes() : Enumerable.Empty<Type>()).ToList();
Or you can use a reusable Union overload:
public static IEnumerable<T> Union<T>(this IEnumerable<IEnumerable<T>> source)
{
var set = new HashSet<T>();
foreach (var s in source)
{
foreach (var item in s)
{
if (set.Add(item))
yield return item;
}
}
}
Then your code turns to:
var allTypes = new [] { group, group2 }.Where(x => x != null).Select(x => x.GetTypes()).Union().ToList();
The advantage of this approach is that you can have more than two sequences forming a union.
All you need here is a method to get the types of a group that can support a null parameter, since yours doesn't. It's a pretty simple method to write:
public static IEnumerable<Type> MyGetTypes(Group group)
{
if(group == null)
return Enumerable.Empty<Type>();
else
return group.GetTypes();
}
(You can make it an extension method if you want)
You can now write your original code as:
var allTypes = MyGetTypes(group).Union(MyGetTypes(group2)).ToList();
We could also generalize this instead of making this method so specific, if we wanted.
public static TResult Use<TSource, TResult>(TSource source,
Func<TSource, TResult> selector,
TResult defaultValue = default(TResult))
{
if (source == null)
return defaultValue;
else
return selector(source);
}
This would let us write:
var allTypes = group.GetTypes()
.Union(group2.Use(g => g.GetTypes(), Enumerable.Empty<Type>()))
.ToList();
When C# 6.0 comes out and we get access to the ?. operator you'd also be able to write the code out like so:
var allTypes = group.GetTypes()
.Union(group2?.GetTypes() ?? Enumerable.Empty<Type>())
.ToList();
This allows the null group to propagate to a null collection of types, rather than throwing, and then allows that null value to be substituted with an empty collection, which Union will support. This operator is more or less a built in version of our Use method, but it allows us to avoid needing to use a lambda, making it noticeably more concise.
The best I've found for putting a null check in one line is the ternary operator.
List<Type> allTypes = group2 == null ?
group.GetTypes()
: group.GetTypes().Union(group2.GetTypes()).ToList();
For this kind of situation, I typically create a new extension method. E.g.:
public static IEnumerable<T> SafeUnion<T>(
this IEnumerable<T> source1, IEnumerable<T> source2)
{
return source1 != null ?
(source2 != null ? source1.Union(source2) : source1) : source2;
}
Or whatever specific logic makes the most sense in your case (the above will allow either enumerable to be null...you might want to allow only the second, for example).
Some curmudgeons may feel that the OP is incapable of adapting this idea to his own needs. I think he probably would have no trouble, and without declarations for the variables I can't show precisely what that would look like. But it would be something a bit like this:
public static List<Type> SafeUnion(this Group group1, Group group2)
{
return (group2 != null ?
group1.GetTypes().Union(group2.GetTypes()) : group1.GetTypes();
}
Of course, the Group type needs to be replaced by whatever the type of those variables actually is. This example also doesn't allow group1 to be null. If that's required, presumably the reader can figure that change out on their own.

sorting list of objects with null properties using linq

I have an object model MyObject that contains a nullable byte as one of its properties.
How do I sort a list of MyObjects on this key so that the list is ordered by ascending based on the values of this properties, with the objects that have the null appearing last.
Thanks for your suggestions.
Linqs OrderBy comes with an overload which accepts an IComparer. This way you can sort the objects all the way you want.
Quick example:
public class NullByteComparer : IComparer<byte?>
{
public int Compare(byte? a, byte? b)
{
if (a == b)
return 0;
if (a == null)
return 1;
if (b == null)
return -1;
return return a < b ? -1 : 1;
}
}
Use it
yourObjects.OrderBy(x => x.NullByteProperty, new NullByteComparer());
Create a custom implementation of the IComparer<byte?> interface.
Use ?? operator to force null values to the back, like this:
var res = myList.OrderBy(v => (uint?)v.NullableByteProp ?? uint.MaxValue);
You need to cast to uint?, because otherwise your nulls will sort together with your 0xFFs.
You can use the GetValueOrDefault() function to provide a value when null equal to Byte.MaxValue
var orderedValues = values.OrderBy(v => v.GetValueOrDefault(Byte.MaxValue));

Linq to objects when object is null VS Linq to SQL

I have this Linq to object query:
var result = Users.Where(u => u.Address.Country.Code == 12)
I get an exception if the Address or the Country are null.
Why this query doesn't check if the address is null and just after that procced?
This way I won't need to write this terrible query:
var result = Users.Where(u => u.Address != null &&
u.Address.Country != null &&
u.Address.Country.Code == 12)
In Linq to SQL the first query wiil do the job(from other reasons of course).
Is the a way to avoid the "null checks" in linq to object?
Unfortunately, "null" is treated inconsistently in C# (and in many other programming languages). Nullable arithmetic is lifted. That is, if you do arithmetic on nullable integers, and none of the operands are null, then you get the normal answer, but if any of them are null, you get null. But the "member access" operator is not lifted; if you give a null operand to the member access "." operator, it throws an exception rather than returning a null value.
Were we designing a type system from scratch, we might say that all types are nullable, and that any expression that contains a null operand produces a null result regardless of the types of the operands. So calling a method with a null receiver or a null argument would produce a null result. That system makes a whole lot of sense, but obviously it is far too late for us to implement that now; millions upon millions of lines of code have been written that expects the current behaviour.
We have considered adding a "lifted" member access operator, perhaps notated .?. So you could then say where user.?Address.?Country.?Code == 12 and that would produce a nullable int that could then be compared to 12 as nullable ints normally are. However, this has never gotten past the "yeah, that might be nice in a future version" stage of the design process so I would not expect it any time soon.
UPDATE: The "Elvis" operator mentioned above was implemented in C# 6.0.
No, it is a null reference exception just like accessing var x = u.Address.Country.Code; would be a NullReferenceException.
You must always make sure what you are de-referencing is not null in LINQ to objects, as you would with any other code statements.
You can do this either using the && logic you have, or you could chain Where clauses as well (though this would contain more iterators and probably perform slower):
var result = Users.Where(u => u.Address != null)
.Where(u.Address.Country != null)
.Where(u.Address.Country.Code == 12);
I've seen some Maybe() extension methods written that let you do the sort of thing you want. Some people do/don't like these because they are extension methods that operate on a null reference. I'm not saying that's good or bad, just that some people feel that violates good OO-like behavior.
For example, you could create an extension method like:
public static class ObjectExtensions
{
// returns default if LHS is null
public static TResult Maybe<TInput, TResult>(this TInput value, Func<TInput, TResult> evaluator)
where TInput : class
{
return (value != null) ? evaluator(value) : default(TResult);
}
// returns specified value if LHS is null
public static TResult Maybe<TInput, TResult>(this TInput value, Func<TInput, TResult> evaluator, TResult failureValue)
where TInput : class
{
return (value != null) ? evaluator(value) : failureValue;
}
}
And then do:
var result = Users.Where(u => u.Maybe(x => x.Address)
.Maybe(x => x.Country)
.Maybe(x => x.Code) == 12);
Essentially, this just cascades the null down the chain (or default value in the case of a non-reference type).
UPDATE:
If you'd like to supply a non-default failure value (say Code is -1 if any part is null), you'd just pass the new failure value into Maybe():
// if you wanted to compare to zero, for example, but didn't want null
// to translate to zero, change the default in the final maybe to -1
var result = Users.Where(u => u.Maybe(x => x.Address)
.Maybe(x => x.Country)
.Maybe(x => x.Code, -1) == 0);
Like I said, this is just one of many solutions. Some people don't like being able to call extension methods from null reference types, but it is an option that some people tend to use to get around these null cascading issues.
Currently, however, there is not a null-safe de-reference operator built into C#, so you either live with the conditional null checks like you had before, chain your Where() statements so that they will filter out the null, or build something to let you cascade the null like the Maybe() methods above.

Categories

Resources