Add a filtering mechanism to expression node types registered by names

Description

The MethodCallExpressionNodeTypeRegistry has been replaced by an interface (INodeTypeProvider) with several implementations. One of them, the MethodNameBasedNodeTypeRegistry, provides support for registering expression node parsers by name (rather than MethodInfo). Since the method name is usually not enough to distinguish query operators, a registration also contains a filter predicate that determines whether a node parser is suitable for parsing a specific query operator method.

Consider the following example:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class MyContainsExpressionNode : ResultOperatorExpressionNodeBase { public static readonly MethodInfo[] SupportedMethods = new[] { GetSupportedMethod (() => Queryable.Contains<object> (null, null)), GetSupportedMethod (() => Enumerable.Contains<object> (null, null)), }; public static readonly NameBasedRegistrationInfo[] SupportedMethodNames = new[] { new NameBasedRegistrationInfo ( "Contains", mi => mi.DeclaringType != typeof (string) && typeof (IEnumerable).IsAssignableFrom (mi.DeclaringType) && (mi.IsStatic && mi.GetParameters().Length == 2 || !mi.IsStatic && mi.GetParameters().Length == 1)) }; // ... }

This code defines that the given MyContainsExpressionNode is registered for the Contains query operators defined by the Queryable and Enumerable classes, and, in addition, for all methods called "Contains" (with the right argument count) declared by classes implementing IEnumerable. Only "string" is exempt, since string.Contains is usually not desired to be seen as a query operator.

(This code is how the ContainsExpressionNode class is currently defined in re-linq.)

To use such a custom expression node parser, create a MethodNameBasedNodeTypeRegistry when creating the QueryParser in your LINQ provider.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 private static IQueryParser CreateQueryParser () { var customNodeTypeRegistry = new MethodInfoBasedNodeTypeRegistry(); // Register custom node parsers here: // customNodeTypeRegistry.Register (MyExpressionNode.SupportedMethods, typeof (MyExpressionNode)); // Alternatively, use the CreateFromTypes factory method. // Use MethodNameBasedNodeTypeRegistry to register parsers by query operator name instead of MethodInfo. var nodeTypeProvider = ExpressionTreeParser.CreateDefaultNodeTypeProvider (); nodeTypeProvider.InnerProviders.Add (customNodeTypeRegistry); var transformerRegistry = ExpressionTransformerRegistry.CreateDefault (); // Register custom expression transformers here: // transformerRegistry.Register (new MyExpressionTransformer()); var processor = ExpressionTreeParser.CreateDefaultProcessor (transformerRegistry); // Add custom processors here: // processor.InnerProcessors.Add (new MyExpressionTreeProcessor()); var expressionTreeParser = new ExpressionTreeParser (nodeTypeProvider, processor); var queryParser = new QueryParser (expressionTreeParser); return queryParser; }

Status

Assignee

Fabian Schmied

Reporter

Fabian Schmied

Labels

Time tracking

3h

Components

Fix versions

Priority

Normal