Reputation: 3675
This concern comes up when I read this Deep Null checking, is there a better way?
and this
C# elegant way to check if a property's property is null
Say I want to check if all properties are NOT null or there is any property is NOT null. (shallow properties)
SearchCriteria object:
Keyword (Searches Name and Description) != null ||
SectorId != null ||
IndustryId != null ||
HasOption != null ||
HasFutures != null ||
30 properties to go...
As we can see, the syntax is somehow hard to read. And I want something like
SearchCriteria
.Has(criteria => criteria.Keywork)
.Has(criteria => criteria.SectorId)
.Has(criteria => criteria.HasOption)
.etc
(in case we want all above properties are NOT null)
OR
SearchCriteria
.Has(criteria => criteria.Keywork).Or()
.Has(criteria => criteria.SectorId).Or()
.Has(criteria => criteria.HasOption).Or()
.etc
(In case we want any property is NOT null)
OR
SearchCriteria
.Has(criteria => criteria.Keywork).Or()
.Has(criteria => criteria.SectorId)
.Has(criteria => criteria.HasOption)
.etc
(In case we want Keyword or SectorId has value and HasOption has value.
So do we have any existed project on codeplex for this? Or any elegant approach that can combine both deep null checking and shallow null checking?
Upvotes: 4
Views: 910
Reputation: 1064114
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();
}
}
}
}
Upvotes: 7
Reputation:
Although I do support Marc Gravell's answer to simply write it out fully, if you do insist on not repeating the != null
, you do not need to create any custom methods. LINQ methods can already do what you want, for example like so:
new[] { SearchCriteria }.SelectMany(criteria => new object[] {
criteria.Keywork,
criteria.SectorId,
criteria.HasOption,
...
}).Any(p => p != null)
To also cover the case where SearchCriteria
itself might be null
, you can use
new[] { SearchCriteria }.Where(criteria => criteria != null).SelectMany(...
Upvotes: 2