使用 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;
}
}
我有一个方法有 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;
}
}