/// <summary> /// Create an advice that runs after the advised method only if it completes successfully. /// </summary> /// <param name="linq">Linq</param> /// <param name="advice">Expression (void) of code to be invoked after the advised method</param> /// <returns>Advice</returns> static public Advice Returning(this Advice.Style.Linq.IAfter linq, Expression advice) { return(new Advice((_Method, _Pointer, _Boundary) => { if (_Boundary != null) { return _Boundary.Combine(new Advice.Boundary.Basic.After.Returning.Singleton(Expression.Lambda <Action>(advice).Compile())); } var _signature = _Method.Signature(); if (advice == null) { return null; } if (advice.Type != Runtime.Void) { throw new NotSupportedException(); } var _type = _Method.ReturnType(); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.Module, true); var _body = _method.GetILGenerator(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(OpCodes.Call, Expression.Lambda(advice).CompileToMethod()); _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
/// <summary> /// Create an advice that runs after the advised method only if it exits by throwing an exception. /// </summary> /// <param name="linq">Linq</param> /// <param name="advice">Expression (void) of code to invoke after the advised method</param> /// <returns>Advice</returns> static public Advice Throwing(this Advice.Style.Linq.IAfter linq, Expression advice) { return(new Advice((_Method, _Pointer, _Boundary) => { if (_Boundary != null) { return _Boundary.Combine(new Advice.Boundary.Basic.After.Throwing.Singleton(Expression.Lambda <Action>(advice).Compile())); } var _signature = _Method.Signature(); var _exception = Expression.Parameter(Metadata <Exception> .Type); if (advice == null) { return null; } if (advice.Type != Runtime.Void) { throw new NotSupportedException(); } var _type = _Method.ReturnType(); var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.Module, true); var _body = _method.GetILGenerator(); if (_type == Runtime.Void) { _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Pop); _body.Emit(OpCodes.Call, Expression.Lambda(advice).CompileToMethod()); _body.Emit(OpCodes.Rethrow); _body.EndExceptionBlock(); } else { _body.DeclareLocal(_type); _body.BeginExceptionBlock(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(OpCodes.Stloc_0); _body.BeginCatchBlock(Metadata <Exception> .Type); _body.Emit(OpCodes.Pop); _body.Emit(OpCodes.Call, Expression.Lambda(advice).CompileToMethod()); _body.Emit(OpCodes.Rethrow); _body.EndExceptionBlock(); _body.Emit(OpCodes.Ldloc_0); } _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; })); }
/// <summary> /// Create an advice that runs after the advised method only if it completes successfully. /// </summary> /// <param name="linq">Linq</param> /// <param name="advice">Delegate used to produce an expression of code to be invoked after the advised method : Func(Expression = [expression of target instance of advised method call], IEnumerable(Expression) = [enumerable of expression of argument used to call advised method], Expression = [expression of return value (null if return type is void)]) return an expression(void) of code to invoke after the advised method</param> /// <returns>Advice</returns> static public Advice Returning(this Advice.Style.Linq.IAfter linq, Func <Expression, IEnumerable <Expression>, Expression, Expression> advice) { return(new Advice((_Method, _Pointer, _Boundary) => { if (advice == null) { return null; } var _signature = _Method.Signature(); var _type = _Method.ReturnType(); if (_Boundary != null) { //TODO dynamic implementation will be faster by avoiding boxing/casting var _instance = Expression.Parameter(Metadata <object> .Type); var _arguments = Expression.Parameter(Metadata <object[]> .Type); var _return = Expression.Parameter(Metadata <object> .Type); var _advice = advice(_signature.Instance == null ? null : _signature.Instance.IsValueType ? Expression.Convert(_instance, _signature.Instance) : Expression.TypeAs(_instance, _signature.Instance), new Collection <Expression>(_signature.Parameters.Select((_Parameter, _Index) => _Parameter.IsValueType ? Expression.Convert(Expression.ArrayIndex(_arguments, Expression.Constant(_Index, Metadata <int> .Type)), _Parameter) : Expression.TypeAs(Expression.ArrayIndex(_arguments, Expression.Constant(_Index, Metadata <int> .Type)), _Parameter)).ToArray()), _type == Runtime.Void ? null : _type.IsValueType ? Expression.Convert(_return, _Method.ReturnType()) : Expression.TypeAs(_return, _type)); if (_advice == null) { return null; } if (_advice.Type != Runtime.Void) { throw new NotSupportedException(); } return _Boundary.Combine(new Advice.Boundary.Advanced.After.Returning.Singleton(_Method, Expression.Lambda <Action <object, object[], object> >(_advice, _instance, _arguments, _return).Compile())); } else { var _parameters = _signature.Select(_Type => Expression.Parameter(_Type)).ToArray(); if (_type == Runtime.Void) { var _advice = _signature.Instance == null ? advice(null, _parameters, null) : advice(_parameters[0], _parameters.Skip(1), null); if (_advice == null) { return null; } if (_advice.Type != Runtime.Void) { throw new NotSupportedException(); } var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.Module, true); var _body = _method.GetILGenerator(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(_signature, false); _body.Emit(OpCodes.Call, Expression.Lambda(_advice, _parameters).CompileToMethod()); _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; } else { var _return = Expression.Parameter(_type); var _advice = _signature.Instance == null ? advice(null, _parameters, _return) : advice(_parameters[0], _parameters.Skip(1), _return); if (_advice == null) { return null; } if (_advice.Type != Runtime.Void) { throw new NotSupportedException(); } var _method = new DynamicMethod(string.Empty, _type, _signature, _Method.Module, true); var _body = _method.GetILGenerator(); _body.Emit(_signature, false); _body.Emit(_Pointer, _type, _signature); _body.Emit(OpCodes.Dup); _body.Emit(_signature, false); _body.Emit(OpCodes.Call, Expression.Lambda(_advice, new ParameterExpression[] { _return }.Concat(_parameters)).CompileToMethod()); _body.Emit(OpCodes.Ret); _method.Prepare(); return _method; } } })); }