/// <summary> /// Analyzes the method call expression provided as parameter and /// returns an appropiated member access. /// </summary> /// <param name="methodCall"> /// The method call to analyze. /// </param> /// <param name="context"> /// Current context. /// </param> /// <returns> /// A System.Linq.Expressions.Expression. /// </returns> protected override Expression VisitMethodCall(MethodCallExpression methodCall, QueryContext context) { // note that we are not skipping any MethodCalls var e = new MethodCallVisitEventArgs(methodCall); // throwing away or replacing this method call if any interceptor found if (this.ExtensionsProvider.OnMethodCallVisit(e, context)) { if (e.SubstituteExpression != e.MethodCall) { return(this.Visit(e.SubstituteExpression, context)); } } return(base.VisitMethodCall(methodCall, context)); }
/// <summary> /// Handles the MethodCallVisit event. /// </summary> /// <param name="e"> /// The <see cref="LogicSoftware.DataAccess.Repository.Extended.Events.MethodCallVisitEventArgs"/> instance containing the event data. /// </param> public override void OnMethodCallVisit(MethodCallVisitEventArgs e) { if (e == null) { throw new ArgumentNullException("e"); } if (e.MethodCall.Method.DeclaringType == typeof(ProjectionExtensions)) { var sourceQueryExpression = e.MethodCall.Arguments.First(); var projectionConfig = e.MethodCall.Arguments.Count == 2 ? ((ConstantExpression)e.MethodCall.Arguments.Last()).Value : null; var projectionType = projectionConfig != null ? projectionConfig.GetType() : TypeSystem.GetElementType(e.MethodCall.Type); e.SubstituteExpression = this.ApplySequenceProjection(sourceQueryExpression, projectionType, projectionConfig); } }
/// <summary> /// Notifies interceptors about MethodCallVisit stage in query execution. /// </summary> /// <param name="e"> /// The <see cref="LogicSoftware.DataAccess.Repository.Extended.Events.MethodCallVisitEventArgs"/> instance containing the event data. /// </param> /// <param name="context"> /// The context. /// </param> /// <returns> /// <c>true</c>, if method call was interepted, <c>false</c> otherwise. /// </returns> public bool OnMethodCallVisit(MethodCallVisitEventArgs e, QueryContext context) { if (e == null) { throw new ArgumentNullException("e"); } if (context == null) { throw new ArgumentNullException("context"); } // checking if this method call visit must be intercepted // getting interceptor that subscibed to this method call visit // allowing to specify InterceptVisitAttribute for all methods in class // todo: add caching? InterceptVisitAttribute attribute = e.MethodCall.Method.GetCustomAttributes <InterceptVisitAttribute>().SingleOrDefault() ?? e.MethodCall.Method.DeclaringType.GetCustomAttributes <InterceptVisitAttribute>().SingleOrDefault(); // no suitable interceptors found if (attribute == null) { return(false); } // get from dictionary or create new IQueryInterceptor interceptor; if (!context.Interceptors.TryGetValue(attribute.InterceptorType, out interceptor)) { interceptor = this.AddInterceptorToContext(attribute.InterceptorType, context); } // intercept interceptor.OnMethodCallVisit(e); return(true); }
public override void OnMethodCallVisit(MethodCallVisitEventArgs e) { if (e == null) { throw new ArgumentNullException("e"); } // working with static extension methods with one "this" argument and with instance methods with no arguments // todo: methods with multiple arguments can be implemented too // todo: maybe better check? if ((e.MethodCall.Method.IsStatic && e.MethodCall.Arguments.Count == 1) || (!e.MethodCall.Method.IsStatic && e.MethodCall.Arguments.Count == 0)) { var expressionAttribute = (ExpandWithExpressionAttribute)e.MethodCall.Method.GetCustomAttributes(typeof(ExpandWithExpressionAttribute), false).SingleOrDefault(); if (expressionAttribute == null) { throw new InvalidOperationException(String.Format( CultureInfo.InvariantCulture, "Method '{0}' in '{1}' class has no ExpandWithExpression attribute.", e.MethodCall.Method.Name, e.MethodCall.Method.DeclaringType.Name)); } var declaringType = expressionAttribute.DeclaringType ?? e.MethodCall.Method.DeclaringType; var methodName = expressionAttribute.MethodName ?? e.MethodCall.Method.Name; var expressionMethodInfo = declaringType.GetMethod( methodName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); if (expressionMethodInfo == null) { throw new ArgumentException(String.Format( CultureInfo.InvariantCulture, "Method specified in ExpandWithExpression attribute of '{0}' method in '{1}' class is not found.", e.MethodCall.Method.Name, e.MethodCall.Method.DeclaringType.Name)); } var customExpandedExpression = (LambdaExpression)expressionMethodInfo.Invoke(null, new object[] { this.Scope }); // parameterExpression is object in case of instance method or single (todo: first) argument in case of extension method var parameterExpression = e.MethodCall.Method.IsStatic ? e.MethodCall.Arguments.Single() : e.MethodCall.Object; // validating custom expanded expression if (customExpandedExpression.Parameters.Single().Type != parameterExpression.Type || customExpandedExpression.Body.Type != e.MethodCall.Type) { throw new InvalidOperationException(String.Format( CultureInfo.InvariantCulture, "Method '{0}' in '{1}' class returns invalid expression.", expressionMethodInfo.Name, expressionMethodInfo.DeclaringType.Name)); } // localize expression (replace its parameter with local object expression) var localizedCustomExpandedExpression = new ExpressionParameterReplacer( customExpandedExpression.Parameters.Single(), parameterExpression) .Visit(customExpandedExpression.Body); e.SubstituteExpression = localizedCustomExpandedExpression; } }
/// <summary> /// The MethodCallVisit stage handler. /// </summary> /// <param name="e"> /// The <see cref="LogicSoftware.DataAccess.Repository.Extended.Events.MethodCallVisitEventArgs"/> instance containing the event data. /// </param> /// <remarks> /// Base implementation is empty. /// </remarks> public virtual void OnMethodCallVisit(MethodCallVisitEventArgs e) { }