Задний план
У меня есть пример теста, который проходит, но возникает ошибка, и я не уверен, почему. Я хотел бы выяснить, что происходит, но я новичок в построении Expression и не хочу делать никаких предположений.
Это для механизма фильтрации поиска. Он использует реализацию ServiceStack PredicateBuilder
. По сути, у меня есть список значений, которые я передаю, и я хочу, чтобы он построил дерево выражений. Раньше я делал это только с Func<T<bool>>
, но понял, что мне нужно закончить с Expression<Func<T<bool>>>
. облом.
Цель
Поисковые фильтры, созданные из повторно используемых типов поисковых фильтров, которые построены из Func
s и Expression
s, что позволяет мне передавать имя поля из объекта вместе со значениями, которые я должен сопоставить, и получить что-то, против чего мы можем запустить оператор Where()
. .
Код/выпуск
Общий фильтр "nullable bool", который я пробую, устанавливает допустимые элементы и возвращает функцию, предназначенную для помощи в фильтрации:
public class NullableBoolFilter : IGenericSearchFilter<bool?>
{
public Func<bool?, bool> GetFilterFunc(string valuesToProcess)
{
var acceptableValues = new List<bool?>();
if (string.IsNullOrWhiteSpace(valuesToProcess))
{
// all values acceptable
acceptableValues = new List<bool?>{true, false, null};
}
else
{
if (!valuesToProcess.Contains("0") && !valuesToProcess.Contains("1"))
{
throw new ArgumentException("Invalid Nullable boolean filter attribute specified");
}
if (valuesToProcess.Contains("0"))
{
acceptableValues.Add(false);
}
if (valuesToProcess.Contains("1"))
{
acceptableValues.Add(true);
}
}
Func<bool?, bool> returnFunc = delegate(bool? item) { return acceptableValues.Any(x=>x == item); };
return returnFunc;
}
}
Затем у меня есть еще один фильтр, который наследуется от NullableBoolFilter
и пытается использовать Func:
public class ClaimsReportIsMDLFilter : NullableBoolFilter, ISearchFilter<vSEARCH_ClaimsReport>
{
public Expression<Func<vSEARCH_ClaimsReport, bool>> GetExpression(string valuesToProcess)
{
var theFunc = base.GetFilterFunc(valuesToProcess);
Expression<Func<vSEARCH_ClaimsReport, bool>> mdlMatches = item => theFunc(item.IsMDL);
var predicate = PredicateBuilder.False<vSEARCH_ClaimsReport>();
predicate = predicate.Or(mdlMatches);
return predicate;
}
}
Проходит следующий тест:
public class ClaimsReportIsMDLFilterTests
{
// ReSharper disable InconsistentNaming
private readonly vSEARCH_ClaimsReport ItemWithMDL = new vSEARCH_ClaimsReport { IsMDL = true };
private readonly vSEARCH_ClaimsReport ItemWithoutMDL = new vSEARCH_ClaimsReport { IsMDL = false };
private readonly vSEARCH_ClaimsReport ItemWithNullMDL = new vSEARCH_ClaimsReport { IsMDL = null };
// ReSharper restore InconsistentNaming
[Fact]
public void WithSearchValueOf1_HidesNonMDLAndNull()
{
var sut = this.GetCompiledExpressionForValues("1");
sut.Invoke(ItemWithMDL).Should().BeTrue();
sut.Invoke(ItemWithoutMDL).Should().BeFalse();
sut.Invoke(ItemWithNullMDL).Should().BeFalse();
}
private Func<vSEARCH_ClaimsReport, bool> GetCompiledExpressionForValues(string searchValue)
{
return new ClaimsReportIsMDLFilter().GetExpression(searchValue).Compile();
}
}
Проблема
Когда я на самом деле пытаюсь запустить это, я получаю сообщение об ошибке:
переменная 'param' типа 'vSEARCH_ClaimsReport', на которую ссылается область видимости '', но она не определена
Мне понятно, почему это может произойти - во время его оценки у меня нет реального объекта для передачи в Func
. Тем не менее, я не понимаю, почему мои тесты могут пройти, но на самом деле это не так.
Вопросы
- Почему мои тесты могут пройти, но я все еще получаю эту ошибку?
- Как, черт возьми, я должен начать пытаться исправить это?
- Есть ли относительно простой способ взять это
Func
и превратить его вExpression
, в которое я могу передать поле? - Нужно ли мне отказываться от общей идеи фильтра и каждый класс вручную добавлять выражения в
PredicateBuilder
на основе переданного ввода? Это выполнимо, но кажется, что работа может быть сокращена больше.
NullableBoolFilter
вращается вокруг делегатов, а вашClaimsReportIsMDLFilter
вращается вокруг деревьев выражений. Это почти наверняка проблема. Если вы хотите использовать деревья выражений, вам нужно использовать их последовательно - как только у вас есть дерево выражений, которое ссылается на какой-то локальныйFunc<>
, ничто не сможет преобразовать его в SQL (или что-то еще). - person Jon Skeet   schedule 06.05.2014