I'v been playing around with some shorter hand ways of checking multiple nested objects to see if any are null before proceeding. I'm trying to replace the multiple nested if statements into a single statement if possible using Null-conditional Operators.
So far i have something like this:
if ((Object1?.Object2?.Object3?.Object4 != null) ? true : false)
{
...
}
Would the above be effective at identifying if either Object1 2 3 or 4 is null and return a false if so? I'm interested to hear if anyone has any better solutions?
TIA
You don't need to return false or true - boolean condition itself has boolean value:
if (Object1?.Object2?.Object3?.Object4 != null)
This part is a completely valid option for checking nested objects if any of them is null. You can find exactly same example in null-conditional operator documentation:
// null if customers, the first customer, or Orders is null
int? count = customers?[0]?.Orders?.Count();
And explanation:
The last example demonstrates that the null-condition operators are
short-circuiting. If one operation in a chain of conditional member
access and index operation returns null, then the rest of the chain’s
execution stops.
The code
public void Foo()
{
if ((Object1?.Object2?.Object3?.Object4 != null) ? true : false)
{
...
}
}
is logically equivalent to
public void Foo()
{
if ((NullCheck(Object1) != null) ? true : false)
{
...
}
}
private Object4Type NullCheck(Object1Type object1)
{
if(!Object.RefrenceEquals(object1, null)) //This is "Object1?."
{
var tmpObject2 = tmpObject1.Object2;
if(!Object.RefrenceEquals(tmpObject2, null)) //This is "Object2?."
{
var tmpObject3 = tmpObject2.Object3;
if(!Object.RefrenceEquals(tmpObject3, null)) //This is "Object3?."
{
return tmpObject3.Object4;
}
}
}
return default(Object4Type);
}
or if Object4Type is a struct
public void Foo()
{
if ((NullCheck(Object1) != null) ? true : false)
{
...
}
}
private Nullable<Object4Type> NullCheck(Object1Type object1)
{
if(!Object.RefrenceEquals(object1, null)) //This is "Object1?."
{
var tmpObject2 = tmpObject1.Object2;
if(!Object.RefrenceEquals(tmpObject2, null)) //This is "Object2?."
{
var tmpObject3 = tmpObject2.Object3;
if(!Object.RefrenceEquals(tmpObject3, null)) //This is "Object3?."
{
return tmpObject3.Object4;
}
}
}
return default(Nullable<Object4Type>);
}
So your ... will only be run if all objects are not null and if a lower level object is null, the later objects never get evaluated.
What you have is currently the best way to do exactly what you want. I wanted to answer in order to illustrate what's necessary if you don't have access to the latest C# 6 language features. This is the next most developer-friendly way to make the same check in .NET 3.5-4.0:
//boilerplate, off in your extension method library
public static TOut OrDefault<TIn, TOut>(this TIn input,
Func<TIn, TOut> possiblyNullFunc)
{
try { return possiblyNullFunc(input); }
catch (NullReferenceException) //for most reference types
{ return default(TOut); }
catch (InvalidOperationException) //for Nullable<T>
{ return default(TOut); }
}
...
//usage
if (Object1.OrDefault(o=>o.Object2.Object3.Object4) != null)
{
...
}
It functions pretty well, until you try to use InvalidOperationException in your own classes for situations other than null member access.
Still beats the pants off this, especially if you have to make this check a lot:
if(Object1 != null
&& Object1.Object2 != null
&& Object1.Object2.Object3 != null
&& Object1.Object2.Object3.Object4 != null)
{
...
}
Related
public class A
{
public B obj{get; set;}
public A()
{
obj=new B();
}
}
public class B
{
public C obj{get; set;}
public B()
{
obj=new C();
}
}
public class C
{
public D obj{get; set;}
public C()
{
//obj=null;
obj=new D();
}
}
public class D
{
public string s{get;set;}
public D()
{
//s="Some string";
s=null;
}
}
public class Program
{
public static void Main(string[] args)
{
A testObject = new A();
if(testObject!=null && testObject.obj!=null && testObject.obj.obj!=null && testObject.obj.obj.obj!=null && testObject.obj.obj.obj.s !=null)
{
Console.WriteLine("String is not null");
return;
}
//This will obviously fails if any of the object of A,B,C,D class is null
//if(testObject.obj.obj.obj.s !=null)
//{
// Console.WriteLine("String is not null");
// return;
//}
Console.WriteLine("String is NULL");
return;
}
}
There exists 4 Classes (A,B,C,D) in Example having chained reference.
I just want to know if there exists better option to check for nullability then the one I used in this Example?
(I want to access string variable 's' from object of class A, so in between if any object is null, an exception is thrown. I want to know if there is better way as this will get worse if there are more deep levels of references , though they are not much recommended but what if it exists.)
http://rextester.com/CGUU62557
(PS:I read some answers , solving this by REFLECTION but that doesn't helps with generic collections.)
You can always use equals:
if(!testObject.equals(null))
{
//your logic
}
And a better way is to use ReferenceEquals:
if(Object.ReferenceEquals(null, testObject))
{
//your logic
}
The ReferenceEquals will return true if your object is null.
testObject!=null && testObject.obj!=null && testObject.obj.obj!=null && testObject.obj.obj.obj!=null etc.
can be rewritten as
testObject?.obj?.obj?.obj?.obj != null
But I would say to be referencing that many layers deep into an object and its properties has "code smell" warning attached to it. It means your code is coupled to the deep internals of your objects, which if they only represent plain data, may not be an issue, but if they represent complex behaviour is probably something you want to avoid.
Im not sure if this is what you want, but you can use the Null-Conditional Operator
if(A?.B?.C?.D == null)
{
//Something was null
}
Test it by making it null.
testObject.obj = null;
This will not throw any exception
if (testObject?.obj?.obj?.obj?.s != null)
This statement testObject?.obj?.obj?.obj?.s return null as a result
You can check it by using Reflection dynamically;
private static bool CheckPropertiesAsNullRecursively(object obj)
{
if (obj == null)
{
return true;
}
var objType = obj.GetType();
if (objType.IsPrimitive || objType == typeof(Decimal) || objType == typeof(String) || objType == typeof(Double))//You should compare the primitive types to determine them
{
return false;
}
var properties = objType.GetProperties();
foreach (var propertyInfo in properties)
{
if (CheckPropertiesAsNullRecursively(objType.GetProperty(propertyInfo.Name).GetValue(obj)))
{
return true;
}
}
return false;
}
Usage;
var val = CheckPropertiesAsNullRecursively(testObject);//If it returns true, at least one property should be null
I'm getting Nullable object must have a value after checking for null on a regular object, after a null check. I've found various questions, mostly regarding linq-to-sql, having the same problem but always with nullable primitive types (as in bool? or DateTime?).
The line causing the exception in my case looks like this:
myDataContext.Orders.Where(y => customer.Address == null || (string.IsNullOrEmpty(customer.Address.Street) || y.Customers.Addresses.Street == customer.Address.Street)))
customer class looks like this:
public class Customer
{
private Address address = null;
public Address Address{get{return address;} set{address=value;}}
}
address property looks like this:
public class Address
{
private string street = null;
public string Street{get{return street ;} set{street =value;}}
}
If I replace above code line with this:
string custStreet = null;
if (customer.Address != null)
{
custStreet = customer.Address.Street;
}
myDataContext.Orders.Where(y =>(customer.Address == null || (string.IsNullOrEmpty(custStreet) || y.Customers.Addresses.Street == custStreet)))
it runs fine. I don't undestand the reason for that. I also don't want to define countless variables before executing the Lambda statement itself.
Please also note that above Lambda statement is part of a much bigger Lambda Where clause that contains a few more of such statements. I know I could work with Expression Trees but having coded this far, I really don't want to switch now.
edit
as the question was answered, I'm going to tell you how I worked around it: I build myself a recursive property initializer. Everything that is not a string, a list/array or a primitive type is thrown against the Activator class. I got the idea from here and made a few changes to it (basically, ignore everything that doesn't need to be initialized and instead of Activator.CreateInstance(Type.GetType(property.PropertyType.Name)); I used Activator.CreateInstance(property.PropertyType)); I'm not even sure if the version used in the original question would work or why anyone would want to use it.)
Contrary to what I wrote in the comments, the problem is that query providers does not even try to reduce the predicate expressions by eliminating the constant parts. As #Servy correctly stated in the comments, they are not forced to do that, and speaking generally there might be a technical reason not doing it, but in reality people tend to use such conditions in their query expressions and expect them to work as if they are evaluated in LINQ to Objects.
I've seen many questions with similar usage, the last being LINQ to Entities conditionals give weird results, and the "standard" comment/answer is - use chained Where with ifs or some predicate builder. Then I start thinking - ok, the providers don't do that, so why don't we do that ourselves then - after all, we are developers and can write (some) code. So I've ended up with the following extension method which uses ExpressionVisitor to modify the query expression tree. I was thinking to post it to the linked question, but since I've get somehow involved in this thread, here you go:
public static class QueryableExtensions
{
public static IQueryable<T> ReduceConstPredicates<T>(this IQueryable<T> source)
{
var reducer = new ConstPredicateReducer();
var expression = reducer.Visit(source.Expression);
if (expression == source.Expression) return source;
return source.Provider.CreateQuery<T>(expression);
}
class ConstPredicateReducer : ExpressionVisitor
{
private int evaluateConst;
private bool EvaluateConst { get { return evaluateConst > 0; } }
private ConstantExpression TryEvaluateConst(Expression node)
{
evaluateConst++;
try { return Visit(node) as ConstantExpression; }
catch { return null; }
finally { evaluateConst--; }
}
protected override Expression VisitUnary(UnaryExpression node)
{
if (EvaluateConst || node.Type == typeof(bool))
{
var operandConst = TryEvaluateConst(node.Operand);
if (operandConst != null)
{
var result = Expression.Lambda(node.Update(operandConst)).Compile().DynamicInvoke();
return Expression.Constant(result, node.Type);
}
}
return EvaluateConst ? node : base.VisitUnary(node);
}
protected override Expression VisitBinary(BinaryExpression node)
{
if (EvaluateConst || node.Type == typeof(bool))
{
var leftConst = TryEvaluateConst(node.Left);
if (leftConst != null)
{
if (node.NodeType == ExpressionType.AndAlso)
return (bool)leftConst.Value ? Visit(node.Right) : Expression.Constant(false);
if (node.NodeType == ExpressionType.OrElse)
return !(bool)leftConst.Value ? Visit(node.Right) : Expression.Constant(true);
var rightConst = TryEvaluateConst(node.Right);
if (rightConst != null)
{
var result = Expression.Lambda(node.Update(leftConst, node.Conversion, rightConst)).Compile().DynamicInvoke();
return Expression.Constant(result, node.Type);
}
}
}
return EvaluateConst ? node : base.VisitBinary(node);
}
protected override Expression VisitConditional(ConditionalExpression node)
{
if (EvaluateConst || node.Type == typeof(bool))
{
var testConst = TryEvaluateConst(node.Test);
if (testConst != null)
return Visit((bool)testConst.Value ? node.IfTrue : node.IfFalse);
}
return EvaluateConst ? node : base.VisitConditional(node);
}
protected override Expression VisitMember(MemberExpression node)
{
if (EvaluateConst || node.Type == typeof(bool))
{
var expressionConst = node.Expression != null ? TryEvaluateConst(node.Expression) : null;
if (expressionConst != null || node.Expression == null)
{
var result = Expression.Lambda(node.Update(expressionConst)).Compile().DynamicInvoke();
return Expression.Constant(result, node.Type);
}
}
return EvaluateConst ? node : base.VisitMember(node);
}
protected override Expression VisitMethodCall(MethodCallExpression node)
{
if (EvaluateConst || node.Type == typeof(bool))
{
var objectConst = node.Object != null ? TryEvaluateConst(node.Object) : null;
if (objectConst != null || node.Object == null)
{
var argumentsConst = new ConstantExpression[node.Arguments.Count];
int count = 0;
while (count < argumentsConst.Length && (argumentsConst[count] = TryEvaluateConst(node.Arguments[count])) != null)
count++;
if (count == argumentsConst.Length)
{
var result = Expression.Lambda(node.Update(objectConst, argumentsConst)).Compile().DynamicInvoke();
return Expression.Constant(result, node.Type);
}
}
}
return EvaluateConst ? node : base.VisitMethodCall(node);
}
}
}
With that extension method in place, all you need is to insert .ReduceConstPredicates() at the end of your queries (before AsEnumerable(), ToList and similar):
var query = myDataContext.Orders
.Where(y => customer.Address == null || string.IsNullOrEmpty(customer.Address.Street) || y.Customers.Addresses.Street == customer.Address.Street)
.ReduceConstPredicates();
The value of the expression customer.Address.Street must be evaluated to its value *before the query can be translated into SQL. That expression cannot be left in the underlying SQL for the database to possibly, or possibly not, evaluate to a value. The query provider has to evaluate it unconditionally in order to determine what the SQL should look like. So yes, you do need to perform the null check outside of the expression. There are of course any number of ways you could do so, but that null checking logic does need to be outside of the expression the query provider translates.
I have the following code that should check if all the properties of class are null. I tried the code below but it didn't work. Why?
You could make a property IsInitialized, that does this internally:
public bool IsInitialized
{
get
{
return this.CellPhone == null && this.Email == null && ...;
}
}
Then just check the property IsInitialized:
if (myUser == null || myUser.IsInitialized)
{ ... }
Another option is the use of reflection to walk over and check all properties, but it seems overkill to me. Also, this gives you the freedom to deviate from the original design (when you choose all properties, except one should be null for example).
//NameSpace
using System.Reflection;
//Definition
bool IsAnyNullOrEmpty(object myObject)
{
foreach(PropertyInfo pi in myObject.GetType().GetProperties())
{
if(pi.PropertyType == typeof(string))
{
string value = (string)pi.GetValue(myObject);
if(string.IsNullOrEmpty(value))
{
return true;
}
}
}
return false;
}
//Call
bool flag = IsAnyNullOrEmpty(objCampaign.Account);
I am suffering a weird problem in C# 4.5.
I have this in my model:
private DataMatrix<T> _matrix;
public DataMatrix<T> Matrix
{
get { return _matrix; }
set { _matrix = value; }
}
And I have a property which uses this:
public object SingleElement
{
get
{
if (Matrix == null) return String.Empty;
if (Matrix.ColumnCount >= 1 && Matrix.RowCount >= 1)
{
return Matrix[0, 0];
}
return null;
}
}
When I run it, before calling SingleElement, the Matrix property is null. But it doesn't return String.Empty, it goes to the second if-statement.
That's my Immediate window says:
I'm a bit confused. What did I do wrong?
This is a most likely a broken equality operator (==), which can be reproduced with the following code:
class Foo
{
public static bool operator == (Foo x, Foo y)
{
return false; // probably more complex stuff here in the real code
}
public static bool operator != (Foo x, Foo y)
{
return !(x == y);
}
static void Main()
{
Foo obj = null;
System.Diagnostics.Debugger.Break();
}
// note there are two compiler warnings here about GetHashCode/Equals;
// I am ignoring those for brevity
}
now at the breakpoint in the immediate window:
?obj
null
?(obj==null)
false
Two fixes:
preferred would be to fix the operator, perhaps adding before anything else:
if(ReferenceEquals(x,y)) return true;
if((object)x == null || (object)y == null) return false;
// the rest of the code...
alternative, if you can't edit that type, is to avoid using the operator; consider using ReferenceEquals explicitly in your code, or performing object-based null checks; for example:
if(ReferenceEquals(Matrix, null)) ...
or
if((object)Matrix == null) ...
The following overloaded ==operator is part of the Calender class in QL.net
public static bool operator ==(Calendar c1, Calendar c2)
{
return (c1.empty() && c2.empty())
|| (!c1.empty() && !c2.empty() && c1.name() == c2.name());
}
public bool empty() { return (object)calendar == null; }
When I try to access the SouthAfricanCalender property, I receive a System.NullReferenceException : Object reference not set to an instance of an object. which prompted me to dig into the source.
public SouthAfrica SouthAfricanCalender
{
get
{
if (_calender == null)
{
_calender = new SouthAfrica();
}
return _calender;
}
set
{
if (_calender == null)
{
_calender = value;
}
}
}
SouthAfrica _calender;
I have ammended the overload as follows based on the answer here
public static bool operator ==(Calendar c1, Calendar c2)
{
if ( object.ReferenceEquals(c1,c2)) return true;
if ((object)c1 == null || (object)c2 == null) return false;
return (c1.empty() && c2.empty())
|| (!c1.empty() && !c2.empty() && c1.name() == c2.name());
}
My question, have I changed the intent of the original code with my amendment?
Edit: any suggestions on how this can be cleaned up further?
No. You ensure that both are objects, and respond accordingly in the places that they aren't (assuming that ReferenceEquals can handle double null). Then you simply execute the same check. The whole .empty() thing is totally unnecessary, by the way, you already know that it's not null, just return the name comparison.
No, you haven't.
It still checks for equality.