我有一个具有n参数的方法。我想用保存这些n参数值的Attribute装饰这种方法。我受到限制,我不能仅提供诸如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);
}
由于我的参数并不总是两倍,因此我转移了一个对象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);
}
}
}
}
(“参数属性”仅包含给定的参数)
在这里,我遍历我拥有的所有有效参数,并将它们强制转换(以进行测试)加倍。然后,我想“调用”该方法,就像提供属性一样。
就像写的一样,该方法只执行一次。
有人可以帮助我解决这个问题吗?谢谢!
答案 0 :(得分:1)
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;
}
}
答案 1 :(得分:0)
您为什么不使用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;
放在需要重新启动代码的位置即可。