Checking for null in an object hierarchy
Checking for null in an object hierarchy
I have a large C# (3.0) object structure originating from a deserialized XML document. I need to know whether a variable deep in the hierarchy is null. The way I do this now is to check every parent object on the way down for null, but this leads to a long repetition of if statements.
I am trying to avoid expensive try-catch blocks.
Is there a smarter way to do this?
edit: For example after a deserialization of an XML application form into an object hierarchy structure there could potentially be a salary value under
applicationForm.employeeInfo.workingConditions.salary
but to find out safely I have to write something like
if (applicationForm.employeeInfo != null) if (applicationForm.employeeInfo.workingConditions != null) if (applicationForm.employeeInfo.workingConditions.salary != null)
because simply using the latter if-statement will of course fail if one of the parent objects is null.
So I am looking for any smarter way to handle this situation.
Answer by Winston Smith for Checking for null in an object hierarchy
Firstly, if you're repeating the logic in more than one place, encapsulate it in a method.
Secondly, you don't need lots of if statements, you just need one with a lot of OR conditions:
if(parent==null || parent.Child == null || parent.Child.GrandChild == null ...
Thirdly, "avoiding expensive try/catch blocks" may be a premature optimization, depending on your scenario. Have you actually tried this and profiled it, and is it really causing a large overhead?
Answer by Fernando for Checking for null in an object hierarchy
can't you iterate?
for (SomeObject obj = someInstance; obj != null; obj = obj.Parent) { //do something }
Answer by Wim Hollebrandse for Checking for null in an object hierarchy
Use reflection.
Create a helper method that takes a parent object and a hierarchical dot notated string for your property names. Then use PropertyInfo and use recursion to go down one property at a time each time checking for null and returning null if so, else continuing down the hierarchy.
Answer by IsmailS for Checking for null in an object hierarchy
CheckForNull(MyType element) { if(element.ChildElement != null) { CheckForNull(element.ChildElement); } else { Console.WriteLine("Null Found"); } }
Answer by Tom Neyland for Checking for null in an object hierarchy
Since you didn't provide all too many details I had to fill in alot of the blanks. Here is a psuo-codeish example of how you might accomplish this via recursion
public bool doesHierarchyContainANull(MyObject ParentObject) { if (ParentObject.getMemberToCheckForNull() == null) return true; else if (ParentObject.isLastInHierarchy()) return false; return doesHierarchyContainANull(ParentObject.getNextInHierarchy()); }
Answer by James for Checking for null in an object hierarchy
You need a recursive function to iterate through the structure and check each node and its children for null. I was working on a sample but IE crashed (typical!!). Will post one later.
Sample
You could do something as simple (assuming you only ever want to just check if the structure is valid) as this:
public void ValidateStructure() { Node root = // get the root node try { ValidateChildren(root); Console.WriteLine("All nodes are valid"); } catch (NullReferenceException) { Console.WriteLine("Structure contained a null node."); } } public void ValidateChildren(Node parent) { // an NullReferenceException would be raised here since parent would be null foreach (var child in parent.Children) { ValidateChildren(child); } }
Answer by Abel for Checking for null in an object hierarchy
You've run into the classic situation where each step in A.B.C.D
may yield null
. Though this is a common scenario, surprisingly there's no common pattern for solving it, other then using a large if-statement with lots of or's (||
).
If each step can return a different class, then there's a rarely used pattern that you can apply: Use a generalized generic extension method with method chaining.
A generalized extension method is not a fixed term but I use it here for emphasizing that the ext. method is applicable to almost all types of objects, hence generalized. According to Bill Wagner in Effective C#, this is bad design. But in some remote cases, like yours, you can use it as long as you know what you're doing and why.
The trick is simple: define a generic extension method and generalize it for all classes that have a default constructor. If the test fails (object is null), the method returns a new object of the same type. Otherwise, it will return the unchanged object itself.
Why is this a good approach for your scenario? Because you don't need to change any existing classes, because it's understandable and promotes readable code, because it keeps type safety (compile time errors instead of runtime errors) and it's simply more concise compared to other approaches.
// extension method: public static class SomeExtentionMethods { public static T SelfOrDefault(this T elem) where T : class, new() /* must be class, must have ctor */ { return elem ?? new T(); /* return self or new instance of T if null */ } } // your code now becomes very easily readable: Obj someObj = getYourObjectFromDeserializing(); // this is it applied to your code: var mySalary = applicationForm.SelfOrDefault(). employeeInfo.SelfOrDefault(). workingConditions.SelfOrDefault(). salary; // now test with one if-statement: if(mySalary.IsEmpty()) // something in the chain was empty else // all's well that ends well :)
The beauty of this approach is that it works with all types of classes (provided they have a ctor), including collections and arrays. If any step is an index step, it will still work (depending on the collection, an invalid index can return null, default or raise an exception):
var x = someObj.SelfOrDefault() .Collection.SelfOrDefault() .Items[1].SelfOrDefault() .Mother.SelfOrDefault() .Father.SelfOrDefault();
Update: expanded a bit and added a more elaborate example
Update: renamed , which implies boolean, to NotNull
SelfOrDefault
, which follows LINQ's naming convention (FirstOrDefault
etc) and implies what it does.
Update: rewritten and reorganized, made code more applicable, hoping to make it more understandable overall :)
Answer by Gabe Moothart for Checking for null in an object hierarchy
You can nest ternary operators. Still a pain, but not as bad as nested ifs.
string salary = (applicationForm.employeeInfo == null) ? null : (applicationForm.employeeInfo.workingConditions == null) ? null : applicationForm.employeeInfo.workingConditions.salary;
If you just want to know whether or not it is null:
bool hasSalary = (applicationForm.employeeInfo == null) ? false : (applicationForm.employeeInfo.workingConditions == null) ? false : (applicationForm.employeeInfo.workingConditions.salary != null);
Answer by Pontus Bremdahl for Checking for null in an object hierarchy
My solution would be something like:
public static TResult SafeGet(this TSource source, Func getResult) { if (source == null) return default(TResult); try { return getResult(source); } catch { return default(TResult); } }
Usage:
Test myTestObject = null; var myStringOrNull = myTestObject.SafeGet(x => x.test.test.test.mySring);
Answer by James Quox for Checking for null in an object hierarchy
I liked the answer by Pontus Bremdahl, but added some more detail for my uses. Code:
/// /// Get a member in an object hierarchy that might contain null references. /// /// /// /// Base object to get member from. /// Member path. /// Returned object if object hierarchy is null. /// Default of requested member type. public TResult SafeGet(TSource source, Func getResult, TResult defaultResult) { // Use EqualityComparer because TSource could by a primitive type. if (EqualityComparer.Default.Equals(source, default(TSource))) return defaultResult; try { return getResult(source); } catch { return defaultResult; } } /// /// Get a member in an object hierarchy that might contain null references. /// /// /// /// Base object to get member from. /// Member path. /// Default of requested member type. public TResult SafeGet(TSource source, Func getResult) { // Use EqualityComparer because TSource could by a primitive type. if (EqualityComparer.Default.Equals(source, default(TSource))) return default(TResult); try { return getResult(source); } catch { return default(TResult); } }
Usage:
// Only authenticated users can run this code if (!HttpContext.Current.SafeGet(s => s.User.Identity.IsAuthenticated)) return; // Get count limit from app.config var countLimit = int.Parse(ConfigurationManager.AppSettings.SafeGet( s => s.Get("countLimit"), "100" // Default 100 if no value is present )); // Is int 6 a class? Always no, but just to show primitive type usage. var is6AClass = 6.SafeGet(i => i.GetType().IsClass);
Update
CSharp version 6 now has this built into it. https://github.com/dotnet/roslyn/wiki/New-Language-Features-in-C%23-6#null-conditional-operators
Null-conditional operators
Sometimes code tends to drown a bit in null-checking. The null-conditional operator lets you access members and elements only when the receiver is not-null, providing a null result otherwise:
int? length = customers?.Length; // null if customers is null Customer first = customers?[0]; // null if customers is null
The null-conditional operator is conveniently used together with the null coalescing operator ??:
int length = customers?.Length ?? 0; // 0 if customers is null
The null-conditional operator exhibits short-circuiting behavior, where an immediately following chain of member accesses, element accesses and invocations will only be executed if the original receiver was not null:
int? first = customers?[0].Orders.Count();
This example is essentially equivalent to:
int? first = (customers != null) ? customers[0].Orders.Count() : null;
Except that customers
is only evaluated once. None of the member accesses, element accesses and invocations immediately following the ?
are executed unless customers
has a non-null value.
Of course null-conditional operators can themselves be chained, in case there is a need to check for null more than once in a chain:
int? first = customers?[0].Orders?.Count();
Note that an invocation (a parenthesized argument list) cannot immediately follow the ?
operator ? that would lead to too many syntactic ambiguities. Thus, the straightforward way of calling a delegate only if it?s there does not work. However, you can do it via the Invoke
method on the delegate:
if (predicate?.Invoke(e) ?? false) { ? }
We expect that a very common use of this pattern will be for triggering events:
PropertyChanged?.Invoke(this, args);
This is an easy and thread-safe way to check for null before you trigger an event. The reason it?s thread-safe is that the feature evaluates the left-hand side only once, and keeps it in a temporary variable.
Answer by Dax Fohl for Checking for null in an object hierarchy
Use the Null monad. It can be in the same file or a different file so long as you using
it.
public static class NullMonad { public static TResult SelectMany(this TIn @in, Func remainder, Func resultSelector) where TIn : class where TOut : class where TResult : class { var @out = @in != null ? remainder(@in) : null; return @out != null ? resultSelector(@in, @out) : null; } }
Then you can use LINQ:
var salary = from form in applicationForm from info in form.employeeInfo from cond in info.workingConditions select cond.salary
This will return the salary if it exists, or null if any of the prior statements result to null, without throwing an exception.
Is it that much better? No, just saves you the slightest bit of repetition, but it looks cool. It also avoids the overhead of creating all the unused "OrDefault" objects in the accepted answer.
Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72
0 comments:
Post a Comment