Skip to content

控制方法执行

ihourglass edited this page Aug 9, 2024 · 2 revisions

控制方法执行

修改方法参数值

OnEntry中可以通过修改MethodContext.Arguments中的元素来修改方法的参数值,为了明确你是想要修改方法参数,还需要将MethodContext.RewriteArguments设置为true来确认修改。

public class DefaultValueAttribute : MoAttribute
{
    public override void OnEntry(MethodContext context)
    {
        context.RewriteArguments = true;

        // 判断参数类型最好通过下面ParameterInfo来判断,而不要通过context.Arguments[i].GetType(),因为context.Arguments[i]可能为null
        var parameters = context.Method.GetParameters();
        for (var i = 0; i < parameters.Length; i++)
        {
            if (parameters[i].ParameterType == typeof(string) && context.Arguments[i] == null)
            {
                context.Arguments[i] = string.Empty;
            }
        }
    }
}

public class Test
{
    // 当传入null值时将返回空字符串
    [DefaultValue]
    public string EmptyIfNull(string value) => value;
}

方法执行拦截

OnEntry的执行时机是在执行方法前,有一些需求场景可能会希望在OnEntry中做参数验证或身份验证等操作,在验证失败后跳过实际方法执行,直接返回,这也就是方法执行拦截。在OnEntry中可以通过MethodContextReplaceReturnValue方法设置返回值,然后在OnEntry执行完毕后就会用ReplaceReturnValue设置的返回值作为方法的返回值直接返回。当然,你也可以在OnEntry中直接抛出异常来阻止实际方法调用:

public class MockAttribute : MoAttribute
{
    public override void OnEntry(MethodContext context)
    {
        // 如果方法无返回值(void),直接传入null即可
        context.ReplaceReturnValue(this, mockValue);
    }
}

修改方法返回值

在方法执行成功后,如果对实际的返回值不满意,可以直接在OnSuccess中通过MethodContextReplaceReturnValue方法替换方法返回值:

public class DefaultResultAttribute : MoAttribute
{
    public override void OnSuccess(MethodContext context)
    {
        // 如果方法无返回值(void),直接传入null即可
        context.ReplaceReturnValue(this, context.ReturnValue ?? defaultValue);
    }
}

处理方法异常

在方法发生抛出异常后,可以在OnException中通过调用MethodContextHandledException方法表明异常已处理并设置返回值:

public class MuteExceptionAttribute : MoAttribute
{
    public override void OnException(MethodContext context)
    {
        // 如果方法无返回值(void),直接传入null即可
        context.HandledException(this, defaultValue);
    }
}

重试执行方法

重试功能可以在遇到指定异常或者返回值非预期值的情况下重新执行当前方法,实现方式是在OnExceptionOnSuccess中设置MethodContext.RetryCount值,在OnExceptionOnSuccess执行完毕后如果MethodContext.RetryCount值大于0那么就会重新执行当前方法。

internal class RetryAttribute : MoAttribute
{
    public override void OnEntry(MethodContext context)
    {
        // 初始化重试次数
        context.RetryCount = 3;
    }

    public override void OnException(MethodContext context)
    {
        // 出现异常减少一次重试次数,当RetryCount减到0时,表示达到重试次数上限,不再重试
        context.RetryCount--;
    }

    public override void OnSuccess(MethodContext context)
    {
        if (context.ReturnValue != ABC)
        {
            // 结果非预期减少一次重试次数,当RetryCount减到0时,表示达到重试次数上限,不再重试
            context.RetryCount--;
        }
        else
        {
            // 结果达到预期,直接将重试次数设置为0,不再进行重试
            context.RetryCount = 0;
        }
    }
}

// 应用RetryAttribute后,Test方法将会重试3次
[Retry]
public void Test()
{
    throw new Exception();
}

使用重试功能需要注意以下几点:

  • 在通过MethodContext.HandledException()处理异常或通过MethodContext.ReplaceReturnValue()修改返回值时会直接将MethodContext.RetryCount置为0,因为手动处理异常和修改返回值就表示你已经决定了该方法的最终结果,所以就不再需要重试了
  • MoAttributeOnEntryOnExit只会执行一次,不会因为重试而多次执行

针对异常处理重试的场景,作者创建了一个独立项目 Rougamo.Retry ,如果只是针对某种异常进行重试操作可以直接使用 Rougamo.Retry