使用 Postsharp 多次执行一个方法

Executing a Method multiple times using Postsharp

我有一个方法有 n 个参数。我想用一个保存这些 n 参数值的属性来装饰这个方法。我受到限制,我不能仅提供 function(param1, param2) 之类的参数来调用此方法,但我可以让函数具有默认参数并在不更改参数 function() 的情况下调用它,并使用我要执行的属性设置了这些参数的方法:

[TestCase]
[Parameters(new object[] { 3, 0 })]
[Parameters(new object[] { 1, 1 })]
[Parameters(new object[] { 4, 4 })]
public void TestParameterized(double x = 0, double y = 0)
{
    Assert.AreEqual(x, y);
}

由于我的参数并不总是双精度的,所以我传输了一个对象数组并相应地转换它。

[Serializable, AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
public class TestCaseAttribute : OnMethodBoundaryAspect
{
    public TestCaseAttribute()
    {
    }

    public override void OnEntry(MethodExecutionArgs args)
    {
        foreach (object attribute in args.Method.GetCustomAttributes(false))
        {
            if (attribute.GetType() == typeof(ParametersAttribute))
            {
                for (int i = 0; i < args.Arguments.Count; i++)
                {
                    args.Arguments.SetArgument(i, Convert.ToDouble(((ParametersAttribute)attribute).Params[i]));
                }

                base.OnEntry(args);
            }
        }

    }
}

(参数属性只包含给定的参数)

在这里,我循环遍历所有有效的参数,并将它们(出于测试目的)加倍。然后我想 "call" 方法,只要提供属性就可以了。

就像写的那样,不幸的是该方法只执行了一次。

谁能帮我解决这个问题?谢谢!

OnMethodBoundaryAspect只是装饰了一个方法的执行。你需要的是一个 MethodInterceptionAspect 来拦截执行。见下文。

我已经使用 CompileTimeInitialize 方法将部分逻辑卸载到 build-time。

而且我敢于将 ParametersAttribute 重命名为 ArgumentsAttribute

我还必须添加一个额外的参数来避免递归。

class Program
{
    static void Main(string[] args)
    {
        new Program().TestParameterized();
    }

    [TestCase]
    [Arguments(new object[] { 3, 0 })]
    [Arguments(new object[] { 1, 1 })]
    [Arguments(new object[] { 4, 4 })]
    public void TestParameterized(double x = 0, double y = 0, bool recursive = false)
    {
        Console.WriteLine($"{x} == {y}: {x == y}");
    }
}

[Serializable, AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
public class TestCaseAttribute : MethodInterceptionAspect
{
    private object[][] argumentsCollection;

    public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo)
    {
        var argumentAttributes = method.GetCustomAttributes(typeof(ArgumentsAttribute)).ToArray();
        argumentsCollection = new object[argumentAttributes.Length][];

        for (int i = 0; i < argumentAttributes.Length; i++)
        {
            object[] givenArguments = ((ArgumentsAttribute)argumentAttributes[i]).Arguments;
            object[] arguments = new object[givenArguments.Length + 1];
            Array.Copy(givenArguments, arguments, givenArguments.Length);
            arguments[givenArguments.Length] = true;
            argumentsCollection[i] = arguments;
        }
    }

    public override void OnInvoke(MethodInterceptionArgs args)
    {
        if ((bool)args.Arguments[args.Arguments.Count - 1])
        {
            args.Proceed();
            return;
        }

        foreach (var arguments in argumentsCollection)
        {
            args.Method.Invoke(args.Instance, arguments);
        }
    }
}

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
class ArgumentsAttribute : Attribute
{
    public object[] Arguments { get; }

    public ArgumentsAttribute(object[] arguments)
    {
        Arguments = arguments;
    }
}