如何在深层 Lambda 表达式中检查 null 值?
例如,假设我有一个嵌套多层的类结构,并且想要执行以下 Lambda 表达式:
x => x.Two.Three.Four.Foo
我希望它在Two、Three或Four为null时返回null,而不是抛出System.NullReferenceException异常。
public class Tests
{
// This test will succeed
[Fact]
public void ReturnsValueWhenClass2NotNull()
{
var one = new One();
one.Two = new Two();
one.Two.Three = new Three();
one.Two.Three.Four = new Four();
one.Two.Three.Four.Foo = "blah";
var result = GetValue(one, x => x.Two.Three.Four.Foo);
Assert.Equal("blah", result);
}
// This test will fail
[Fact]
public void ReturnsNullWhenClass2IsNull()
{
var one = new One();
var result = GetValue(one, x => x.Two.Three.Four.Foo);
Assert.Equal(null, result);
}
private TResult GetValue<TModel, TResult>(TModel model, Expression<Func<TModel, TResult>> expression)
{
var func = expression.Compile();
var value = func(model);
return value;
}
public class One
{
public Two Two { get; set; }
}
public class Two
{
public Three Three { get; set; }
}
public class Three
{
public Four Four { get; set; }
}
public class Four
{
public string Foo { get; set; }
public string Bar { get; set; }
}
}
更新:
一种解决方法是像这样捕获NullReferenceException:
private TResult GetValue<TModel, TResult>(TModel model, Expression<Func<TModel, TResult>> expression)
{
TResult value;
try
{
var func = expression.Compile();
value = func(model);
}
catch (NullReferenceException)
{
value = default(TResult);
}
return value;
}
但我不希望因捕获我认为并非异常的异常而产生开销。我预计在我的领域中这种情况会经常出现。
更新2:
另一种解决方法是像这样修改属性获取器:
public class One
{
private Two two;
public Two Two
{
get
{
return two ?? new Two();
}
set
{
two = value;
}
}
}
对于我的领域来说大部分都没问题,但有时我确实希望一个属性返回null。我查看了Josh E的回答,认为在某些情况下它非常接近我需要的。