Reputation: 5894
In my code I have to access values calling several property getters:
IFoo1 a = objA.Prop1.Value;
IFoo2 b = objB.Prop2.Prop3.Value;
IFoo3 c = objC.Prop4.Prop5.Prop6.Value;
Every property can be null. So to access every value I must use nested if-blocks:
IFoo2 b = null;
if(objB.Prop2!=null)
{
if(objB.Prop2.Prop3!=null)
{
b = objB.Prop2.Prop3.Value;
}
}
How can I improve this code to reduce amount of if-blocks? Can I use any lambda expressions, LINQ, IExpression, etc, to somehow replace it with:
IFoo2 b = GetVal(objB.Prop2.Prop3.Value);
All PropX are of different types and I have hundreds of such properties. I must use .NET 3.5 or at least .NET 4.0. I can not use any later versions.
IMPORTANT EDIT:
I must also use Visual Studio 2012 and 2013. I can not target VS 2015.
Upvotes: 1
Views: 2724
Reputation: 27367
This will do it, but it's very very quick and dirty. Some obvious flaws:
if (a != null && a.b != null && a.b.c != null) return a.b.c.d;
which is a fairly common patternpublic static T GetOrNull<T>(Expression<Func<T>> expression)
where T : class
{
var memberExpressions = new List<MemberExpression>();
var membExpress = expression.Body as MemberExpression;
while (membExpress != null)
{
memberExpressions.Add(membExpress);
membExpress = membExpress.Expression as MemberExpression;
}
memberExpressions.Skip(1).Reverse();
foreach(var membExpr in memberExpressions.Skip(1).Reverse()) {
var lambdaExpr = Expression.Lambda(membExpr);
var currentRes = lambdaExpr.Compile().DynamicInvoke();
if (currentRes == null)
return null;
}
return (T)Expression.Lambda(expression.Body).Compile().DynamicInvoke();
}
And use it like this:
var tmp = new classA();
var res = GetOrNull(() => tmp.Prop1.Prop2);
res.Dump(); //Gives null
tmp.Prop1 = new classA.classB();
tmp.Prop1.Prop2 = new classA.classB.classC();
res = GetOrNull(() => tmp.Prop1.Prop2);
res.Dump(); //returns object of type `classC`
Upvotes: 1
Reputation: 292475
Unfortunately you need C# 6 to use the null-conditional operator (?.
).
However, you can simulate it with extension methods like these:
static class Extensions
{
public static TReturn NCR<T, TReturn>(this T instance, Func<T, TReturn> getter)
where T : class
where TReturn : class
{
if (instance != null)
return getter(instance);
return null;
}
public static TReturn NCR<T, TReturn>(this T? instance, Func<T, TReturn> getter)
where T : struct
where TReturn : class
{
if (instance != null)
return getter(instance.Value);
return null;
}
public static TReturn? NCV<T, TReturn>(this T instance, Func<T, TReturn> getter)
where T : class
where TReturn : struct
{
if (instance != null)
return getter(instance);
return null;
}
public static TReturn? NCV<T, TReturn>(this T? instance, Func<T, TReturn> getter)
where T : struct
where TReturn : struct
{
if (instance != null)
return getter(instance.Value);
return null;
}
}
(NC stands for Null-Conditional, R stands for Reference type, V stands for Value type; it's ugly, but unfortunately C# doesn't allow method overloads that differ only by the generic constraints)
You can use them like this:
IFoo3 c = objC.NCR(_ => _.Prop4)
.NCR(_ => _.Prop5)
.NCR(_ => _.Prop6)
.NCR(_ => _.Value);
(use NCV instead of NCR if the property to get returns a value type)
It's still too verbose, but at least it's easier to see what the code is doing.
Upvotes: 2
Reputation: 77886
Best you can probably do is using a compound if
condition like
IFoo2 b = null;
if(objB.Prop2 != null && objB.Prop2.Prop3 != null)
{
b = objB.Prop2.Prop3.Value;
}
(OR) using a Ternary Operator
like
IFoo2 b = (objB.Prop2 != null && objB.Prop2.Prop3 != null) ? objB.Prop2.Prop3.Value : null;
Upvotes: 0
Reputation: 4024
.NET 4.6 now has a ?. operator that solves this exact problem.
http://www.volatileread.com/Wiki?id=2104
This allows you to write it like this.
IFoo3 c = objC?.Prop4?.Prop5?.Prop6?.Value;
You might get around this by creating a helper function, but the clarity and simplicity of the code won't get anywhere near this. If possible, upgrade to get that feature.
Upvotes: -1