A new mechanism has been added that allows re-linq-based providers to customize the expression processing pipeline in the re-linq front-end. This feature can be used to implement complex expression transformations (eg., expression visitor runs), to remove the partial evaluation feature included in the expression pipeline by default, or to add an additional partial evaluation step after the transformation step has run.
Note that for simple expression transformations, the predefined expression transformation support should be used as it is more efficient than an additional expression tree run.
The following classes and interfaces are involved:
- Interface IExpressionTreeProcessingStep: Implement this interface to define a custom processing step. When creating a QueryParser, include this step in the pipeline. The Process method will then be called for the root node of the expression tree when a query is parsed.
- Class PartialEvaluationStep: This is a predefined step that evaluates parts of an expression tree in-memory. An instance of this step is automatically included in the pipeline created by ExpressionTreeParser.CreateDefaultProcessingSteps.
- Class ExpressionTransformationStep: This is a predefined step that executes a sequence of expression transformations when a query is parsed. An instance of this step is automatically included in the pipeline created by ExpressionTreeParser.CreateDefaultProcessingSteps.
To customize the processing steps executed by a LINQ provider, use a QueryParser that includes the steps to be processed. You can use the ExpressionTreeParser.CreateDefaultProcessingSteps method to get the steps included by default.
The following example creates a highly customizable instance of a class MyQueryable<T>, which has a custom processing step registered after all default steps have executed. It is of course possible to use a dependency injection container rather than manually composing the queryProvider.
(Note that QueryParser and DefaultQueryProvider do not change state between different queries, so they can be stored and reused with "singleton" semantics.)