Выполнение метода несколько раз с использованием Postsharp - PullRequest
1 голос
/ 08 мая 2019

У меня есть метод с n-параметром.Я хочу украсить этот метод с атрибутом, который содержит значения для этих n-параметров.Я ограничен в том, что я не могу вызвать этот метод, просто предоставив параметры типа function(param1, param2), но я могу позволить функции иметь параметр по умолчанию и вызывать его без изменения параметров function(), с Атрибутом, который я хочу выполнить метод с этими параметрамиset:

[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);
}

Так как мои параметры не всегда удваиваются, я передаю объект Array и применяю его соответственно.

[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);
            }
        }

    }
}

(Атрибут параметра просто содержит заданные параметры)

Здесь я перебираю все имеющиеся у меня параметры, что работает, и приводю их (для целей тестирования) к удвоению,Затем я хотел бы «вызывать» метод так часто, как предоставляется атрибут.

Как написано, метод выполняется, к сожалению, только один раз.

Может кто-нибудь помочь мне с этой проблемой?Спасибо!

Ответы [ 2 ]

1 голос
/ 10 мая 2019

OnMethodBoundaryAspect просто украшает выполнение метода. Что вам нужно, это MethodInterceptionAspect, который перехватывает выполнение. Смотри ниже.

Я выгрузил часть логики во время сборки, используя метод CompileTimeInitialize.

И я осмелился переименовать 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;
    }
}
0 голосов
/ 08 мая 2019

Почему бы вам не использовать старомодный способ goto?

Примерно так:

foreach (object attribute in args.Method.GetCustomAttributes(false))
{
restart:
   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);
   if(somecondition)
   {
       goto restart;
   }
   }
}

Просто нужно поместить restart и goto restart; туда, где вам нужно перезапустить код.

...