Deep Null Checking, Is There a Better Way

Deep null checking, is there a better way?

We have considered adding a new operation "?." to the language that has the semantics you want. (And it has been added now; see below.) That is, you'd say

cake?.frosting?.berries?.loader

and the compiler would generate all the short-circuiting checks for you.

It didn't make the bar for C# 4. Perhaps for a hypothetical future version of the language.

Update (2014):
The ?. operator is now planned for the next Roslyn compiler release. Note that there is still some debate over the exact syntactic and semantic analysis of the operator.

Update (July 2015): Visual Studio 2015 has been released and ships with a C# compiler that supports the null-conditional operators ?. and ?[].

Deep null check inside linq expression, is there a better way?

Try to do not do any null checks in LINQ to Entities query. EF should handle nulls automatically:

_collection.Select(x=> new CollectionModel
{
Title = x.CollectionValues!.FirstOrDefault(x => x.Amount == amount)!
.TranslationTitle.TranslationValues!
.FirstOrDefault(x => x.LanguageId == languageId)!
.Value ?? ""
}
);

Eliminate IF checks in LINQ deep structure

You can create a simple extension method capable of applying a projection to a possibly null value that propagates null values instead of throwing an exception: (Note that different people like using different names for this operation; feel free to call the method whatever makes the most sense to you.)

public static TResult Use<TSource, TResult>(
this TSource obj, Func<TSource, TResult> selector)
where TSource : class
where TResult : class
{
return obj == null ? null : selector(obj);
}

With this your code can be condensed into the following:

var name = doc.Root.Element("E1")
.Use(element => element.Elements("E2"))
.Use(elements => elements.SingleOrDefault(
element => element.Attribute("id")
.Use(att => att.Value) == "ABC"))
.Use(element => element.Attribute("name").Value);

C# elegant way to check if all shallow properties are null (or any property is not null)

Frankly, I'd stick with the simple version involving || or &&, == null or != null. It it direct and efficient, and allows immediate short-circuiting. If you are going to be doing this lots, you could perhaps write a utility class that uses meta-programming (Expression or ILGenerator maybe) to create an optimized method once per-type that checks all the properties, then:

if(MyHelper.AllNull(obj)) ... // note this is probably actually generic

Full example:

using System;
using System.Linq.Expressions;
using System.Reflection;

static class Program
{
static void Main()
{
bool x = MyHelper.AnyNull(new Foo { }); // true
bool y = MyHelper.AnyNull(new Foo { X = "" }); // false
}
}
class Foo
{
public string X { get; set; }
public int Y { get; set; }
}
static class MyHelper
{
public static bool AnyNull<T>(T obj)
{
return Cache<T>.AnyNull(obj);
}
static class Cache<T>
{
public static readonly Func<T, bool> AnyNull;

static Cache()
{
var props = typeof(T).GetProperties(
BindingFlags.Instance | BindingFlags.Public);

var param = Expression.Parameter(typeof(T), "obj");
Expression body = null;

foreach(var prop in props)
{
if (!prop.CanRead) continue;

if(prop.PropertyType.IsValueType)
{
Type underlyingType = Nullable.GetUnderlyingType(
prop.PropertyType);
if (underlyingType == null) continue; // cannot be null

// TODO: handle Nullable<T>
}
else
{
Expression check = Expression.Equal(
Expression.Property(param, prop),
Expression.Constant(null, prop.PropertyType));
body = body == null ? check : Expression.OrElse(body, check);
}
}
if (body == null) AnyNull = x => false; // or true?
else
{
AnyNull = Expression.Lambda<Func<T, bool>>(body, param).Compile();
}
}
}
}

Is there a more innovative way to handle null exceptions in the following cases?

If you want to just provide new Veet Object if puppy.getVet() is null by using orElseGet

Vet vet = Optional.ofNullable(puppy.getVet()).orElseGet(Vet::new);

If you want to provide default Veet Object if puppy.getVet() is null

Vet vet = Optional.ofNullable(puppy.getVet()).orElseGet(PuppyResponse::getDefaultVet);

This way you don't need to check ifPresent and create responses accordingly

return new PuppyResponse(
puppy.getPuppyId(),
puppy.getName(),
puppy.getAge(),
puppy.getBreed(),
vet.getVetId(),
vet.getName()
);

To provide default Vet Object

private static Vet getDefaultVet(){
Vet v = new Vet();
v.setVetId(0);
v.setName("Default Name");
return v;
}


Related Topics



Leave a reply



Submit