Как проверить, что выражение является короткозамкнутым
-
10-07-2019 - |
Вопрос
У меня есть метод расширения со следующей подписью:
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
...
}
Я написал для него тестовый пример, который гарантирует, что эти два выражения действительно объединены.По крайней мере, для того, чтобы новое выражение, которое я получаю, работало.
Теперь я хотел бы написать еще один тестовый пример, который просто гарантирует, что метод использует короткозамкнутую версию and
.Есть какие-нибудь подсказки, как я могу это сделать?
Я думал, что мог бы просто сделать что-то вроде этого:
[Test]
public void And_PredicatesAreShortCircuited()
{
var predicateNotUsed = true;
Expression<Func<int, bool>> a = x => false;
Expression<Func<int, bool>> b = x =>
{
predicateNotUsed = false;
return true;
};
var foo = new[] { 1, 2, 3, 4, 5, 6, 7 }
.Where(a.And(b).Compile())
.ToArray();
Assert.That(predicateNotUsed);
}
Но я получаю гигантскую красную закорючку под всем этим текстом заявления для b
заявляя , что "Лямбда-выражение с телом оператора не может быть преобразовано в дерево выражений".Итак...есть какие-нибудь варианты?Или это невозможный тест для написания?
Решение
Простое предложение:используйте ссылочный тип вместо типа значения и разыменуйте его по пути, по которому вы не хотите следовать.Передайте значение null и посмотрите, выдает ли оно исключение :)
[Test]
public void And_PredicatesAreShortCircuited()
{
Expression<Func<string, bool>> a = x => false;
Expression<Func<string, bool>> b = x => x.Length > 10;
var foo = new[] { null, null }
.Where(a.And(b).Compile())
.ToArray();
}
Другой альтернативой было бы использовать какую-либо побочную функцию для входных данных (например,передайте что-то, что может быть изменено деревом выражений) но я думаю, что описанное выше, вероятно, будет самым простым подходом :)
Или другая идея:
public T NonVoidFail(T x)
{
Assert.Fail("I shouldn't be called");
return x; // Will never happen
}
Тогда:
[Test]
public void And_PredicatesAreShortCircuited()
{
Expression<Func<int, bool>> a = x => false;
Expression<Func<int, bool>> b = x => NonVoidFail(x);
var foo = new[] { 1, 2, 3, 4, 5, 6, 7 }
.Where(a.And(b).Compile())
.ToArray();
}
Это тот же принцип, но это даст вам более приятное исключение :)