Reputation: 359
I have a Method that has n-parameter. I want to decorate this method with an Attribute that holds values for those n-parameters. I am restricted, that I cannot call this method just providing the parameters like function(param1, param2)
, but I can let the function have default parameter and call it without changing parameters function()
, with the Attribute I want to execute the method with these parameters 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);
}
Since my parameters are not always doubles I transfer a object Array and cast it accordingly.
[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);
}
}
}
}
(The Parameter Attribute simply holds the given parameters)
Here I'm looping through all the parameters I have, which works, and cast them (for testing purposes) to double. Then I would like to "call" the method, as often as the attribute is provided.
Like it is written the method is only executed once unfortunately.
Can anyone help me with this problem? Thank you!
Upvotes: 1
Views: 198
Reputation: 1408
The OnMethodBoundaryAspect
just decorates the execution of a method. What you need is a MethodInterceptionAspect
which intercepts the execution. See below.
I've offloaded part of the logic to build-time using CompileTimeInitialize
method.
And I dared to rename the ParametersAttribute
to ArgumentsAttribute
.
I also had to add an extra parameter to avoid recursion.
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;
}
}
Upvotes: 2