Что ж, в этом случае, если вы не можете использовать Memoization, вы довольно ограничены, поскольку вы действительно можете использовать только стек в качестве своего кэша: у вас нет возможности объявить новую переменную в той области, которую вы ' я буду нуждаться Все, что я могу придумать (и я не утверждаю, что это будет красиво), это будет делать то, что вы хотите, но сохраняете необходимую вам компоновку, что-то вроде ...
private static bool TestWith<T>(T cached, Func<T, bool> predicate)
{
return predicate(cached);
}
public static Expression<Func<Potion, bool>>
ContainsIngredients(string ingredientType, params string[] ingredients)
{
var predicate = PredicateBuilder.False<Potion>();
// Here, I'm accessing p.Ingredients several times in one
// expression. Is there any way to cache this value and
// reference the cached value in the expression?
foreach (var ingredient in ingredients)
{
var temp = ingredient;
predicate = predicate.Or (
p => TestWith(p.Ingredients,
i => i != null &&
i.Contains(ingredientType) &&
i.Get(ingredientType).Contains(temp));
}
return predicate;
}
Вы можете объединить результаты нескольких вызовов TestWith в более сложное логическое выражение, где это необходимо - кэширование подходящего дорогостоящего значения при каждом вызове, или вы можете вложить их в лямбда-выражения, передаваемые в качестве второго параметра, для обработки вашего сложного глубокого иерархии.
Хотя было бы довольно сложно читать код, и, поскольку вы могли бы вводить больше стековых переходов со всеми вызовами TestWith, от того, повысит ли это производительность, будет зависеть только то, насколько дорогим был ваш ExорогоCall ().
Как примечание, в исходном примере не будет никаких вставок, как предполагает другой ответ, поскольку компилятор выражений, насколько я знаю, не выполняет этот уровень оптимизации.