Как проверить нулевые значения в глубоком выражении lamda?
Скажем, например, у меня есть структура классов, вложенная в несколько слоев, и я хотел выполнить следующую lambda:
x => x.Two.Three.Four.Foo
Я хочу, чтобы он возвращал значение 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; }
}
}
UPDATE:
Одним из решений было бы уловить исключение 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:
Другим решением было бы изменить свойства getters следующим образом:
public class One
{
private Two two;
public Two Two
{
get
{
return two ?? new Two();
}
set
{
two = value;
}
}
}
В основном это нормально для моего домена, но бывают случаи, когда я действительно ожидаю, что свойство вернет null. Я проверил ответ от Josh E как полезный, так как он близок к тому, что мне нужно в некоторых случаях.