Using the PostSharp libraries, is it possible to make it so that if a certain value is returned from a method? For example, we put an attribute on the argument (which is a number) in the method (where we also return the number): if the number is less than zero, then we return just zero. Or if the argument is a reference type and is null.

ps it is clear that the problem is solved by a line of code in the body of the method, this is just a pseudo-task for which it is convenient to show.

UPD Something like this:

public class FooClass { public FooClass( [NotEmpty] string field ) { FieldStr = field; } public string FooValue( [IfNull("Empty")] string source ) { return source; } public readonly string FieldStr; } internal class IfNullAttribute : Attribute { private string v; public IfNullAttribute(string v) { this.v = v; } public string ReturnValue() => v; } 
  • can you add sample code how would you like to use? - Grundy
  • @Grundy, added pseudocode to the header. - anweledig
  • something like default parameters? - Grundy
  • @Grundy, yes, it is - anweledig
  • 2
    @Grundy with AOP everything is possible! The main thing is to know how :). - andreycha

2 answers 2

A more flexible option, with the installation of attributes on the parameters and the ability to define additional conditions. However, it is impossible to do without the attribute of the method level, since it is possible to return control from the method only in the aspect of the method.

We define an attribute for a method that supports early exit:

 [Serializable] public class EarlyReturnAttribute : OnMethodBoundaryAspect { public override void OnEntry(MethodExecutionArgs args) { ParameterInfo[] parameters = args.Method.GetParameters(); for (int i = 0; i < parameters.Length; i++) { foreach (var attribute in parameters[i].GetCustomAttributes<EarlyReturnConditionAttribute>()) { if (attribute.MeetsCondition(args.Arguments[i])) { args.ReturnValue = attribute.ReturnValue; args.FlowBehavior = FlowBehavior.Return; return; } } } base.OnEntry(args); } } 

We define attributes for parameters. To set specific conditions for early exit, we inherit from the EarlyReturnConditionAttribute :

 public abstract class EarlyReturnConditionAttribute : Attribute { public EarlyReturnConditionAttribute(object returnValue) { ReturnValue = returnValue; } public object ReturnValue { get; } public abstract bool MeetsCondition(object value); } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true)] public class IfNullAttribute: EarlyReturnConditionAttribute { public IfNullAttribute(object returnValue) : base(returnValue) { } public override bool MeetsCondition(object value) { return value == null; } } 

We use:

 public class FooClass { [EarlyReturn] public string FooValue([IfNull("Empty")]string source) { return source; } } 
  • What is the need to call the base method before exiting the override? - anweledig
  • 2
    The @anweledig base method will only be called if early exit does not work. Since I did not see the implementation of the base method (perhaps it is not empty), it is better to call it in the "normal script". - andreycha

With PostSharp, you can do this as follows:

 class Program { static void Main(string[] args) { var foo = new FooClass(); Console.WriteLine(foo.FooValue("foo")); // foo Console.WriteLine(foo.FooValue(null)); // bar } } public class FooClass { [ResultAspect] public string FooValue(string source) { return source; } } [Serializable] public class ResultAspect : OnMethodBoundaryAspect { public override void OnExit(MethodExecutionArgs args) { if (args.Arguments[0] == null) args.ReturnValue = "bar"; base.OnExit(args); } } 

Create an aspect inherited from OnMethodBoundaryAspect . Mark them with the desired method. Through the parameter args you can get the values ​​of the arguments with which the method was invoked. Through it, you can set the output value.


Can you make it from OnEntry? To instantly return a value so that null does not get into the body of the method where there is no check.

Can:

 public override void OnEntry(MethodExecutionArgs args) { if (args.Arguments[0] != null) base.OnEntry(args); } 

Or, as suggested by andreycha , inherit from MethodInterceptionAspect :

 [Serializable] public class ResultAspect2 : MethodInterceptionAspect { public override void OnInvoke(MethodInterceptionArgs args) { if (args.Arguments[0] != null) base.OnInvoke(args); } } 
  • and that attribute was at parameter, but not on the method? - Grundy
  • one
    The interceptor method is the easiest solution, but not the most convenient to use. What if there are several parameters? What if for each of them you want your condition? Mark a method with an attribute of the type [Result("paramName", "value")] or [Result(%paramIndex%, "value")] not the most statically typed solution. - andreycha
  • cool option, but can it be done from OnEtry? To return the value instantly, so that null does not get into the body of the method where there is no check. - anweledig pm
  • one
    @anweledig you can. Alternatively, you can still inherit from MethodInterceptionAspect and override OnInvoke . - andreycha