Looking for .net Keywords? Try Ask4Keywords

.NET Framework Класс InvocationExpression


пример

Класс InvocationExpression позволяет вызывать другие лямбда-выражения, которые являются частями одного и того же дерева выражений.

Вы создаете их со статическим методом Expression.Invoke .

Проблема Мы хотим получить предметы, которые имеют «автомобиль» в своем описании. Нам нужно проверить его на нуль, прежде чем искать строку внутри, но мы не хотим, чтобы ее вызывали чрезмерно, так как вычисление могло быть дорогостоящим.

using System;
using System.Linq;
using System.Linq.Expressions;
                    
public class Program
{
    public static void Main()
    {
        var elements = new[] {
            new Element { Description = "car" },
            new Element { Description = "cargo" },
            new Element { Description = "wheel" },
            new Element { Description = null },
            new Element { Description = "Madagascar" },
        };
    
        var elementIsInterestingExpression = CreateSearchPredicate(
            searchTerm: "car",
            whereToSearch: (Element e) => e.Description);
            
        Console.WriteLine(elementIsInterestingExpression.ToString());
            
        var elementIsInteresting = elementIsInterestingExpression.Compile();
        var interestingElements = elements.Where(elementIsInteresting);
        foreach (var e in interestingElements)
        {
            Console.WriteLine(e.Description);
        }
        
        var countExpensiveComputations = 0;
        Action incCount = () => countExpensiveComputations++;
        elements
            .Where(
                CreateSearchPredicate(
                    "car",
                    (Element e) => ExpensivelyComputed(
                        e, incCount
                    )
                ).Compile()
            )
            .Count();
                   
        Console.WriteLine("Property extractor is called {0} times.", countExpensiveComputations);
    }
    
    private class Element
    {
        public string Description { get; set; }
    }
    
    private static string ExpensivelyComputed(Element source, Action count)
    {
        count();
        return source.Description;
    }
    
    private static Expression<Func<T, bool>> CreateSearchPredicate<T>(
            string searchTerm,
            Expression<Func<T, string>> whereToSearch)
    {
        var extracted = Expression.Parameter(typeof(string), "extracted");
    
        Expression<Func<string, bool>> coalesceNullCheckWithSearch =
            Expression.Lambda<Func<string, bool>>(
                Expression.AndAlso(
                    Expression.Not(
                        Expression.Call(typeof(string), "IsNullOrEmpty", null, extracted)
                    ),
                    Expression.Call(extracted, "Contains", null, Expression.Constant(searchTerm))
                ),
                extracted);
                
        var elementParameter = Expression.Parameter(typeof(T), "element");
                
        return Expression.Lambda<Func<T, bool>>(
            Expression.Invoke(
                coalesceNullCheckWithSearch,
                Expression.Invoke(whereToSearch, elementParameter)
            ),
            elementParameter
        );
    }
}

Выход

element => Invoke(extracted => (Not(IsNullOrEmpty(extracted)) AndAlso extracted.Contains("car")), Invoke(e => e.Description, element))
car
cargo
Madagascar
Predicate is called 5 times.

Первое, что нужно отметить, - это то, как фактический доступ к собственности, завернутый в Invoke:

Invoke(e => e.Description, element)

, и это единственная часть, e.Description , а вместо нее extracted параметр string типа передается следующему:

(Not(IsNullOrEmpty(extracted)) AndAlso extracted.Contains("car"))

Еще одно важное замечание - AndAlso . Он вычисляет только левую часть, если первая часть возвращает «false». Ошибочно использовать побитовый оператор «А» вместо него, который всегда вычисляет обе части, и в этом примере завершится с ошибкой NullReferenceException.