在我的应用程序中,我以前使用常规的C#属性来“注释”一个方法。 E.g:
[Foo(SomeKey="A", SomeValue="3")]
[Foo(SomeKey="B", SomeValue="4")]
public void TheMethod()
{
SpecialAttributeLogicHere();
}
SpecialAttributeLogicHere()所做的是反思地查看注释了这种特定方法的所有Foo属性。然后(单独),为所有键和值创建自己的字典。
我现在正试图转移到PostSharp,因为在OnEntry中可以将SpecialAttributeLogic放入一个方面(并从方法体中移除,它更干净!)。 Foo将被扩展OnMethodBoundaryAspect的方面所取代。
我仍然希望以下列方式使用它:
[Foo(SomeKey="A", SomeValue="3")]
[Foo(SomeKey="B", SomeValue="4")]
但是如果Foo有OnEntry,那意味着“SpecialAttributeLogic”将被执行两次。我基本上需要将每个Foo()的所有键和值“收集”到一个字典中,然后我将一些逻辑应用到字典中。
如何使用PostSharp执行此操作(或最佳实践)?谢谢!
答案 0 :(得分:2)
看起来你想在你的方法中建立一个namevaluepair。你不能用方面来做这件事。我建议您使用MethodInterceptionAspect并反映方法上的属性,然后构建您的集合并通过参数(可能使用重载方法)将其传递给方法,或将其设置为类成员。
您可以在编译时反映这些值,以保持最佳性能。
以下是您问题的快速解决方案。它有点难看(你需要进行修改以适应)。还有其他方法,但它们不是“通用的”。
namespace ConsoleApplication12
{
class Program
{
static void Main(string[] args)
{
MyExampleClass ec = new MyExampleClass();
ec.MyMethod();
}
}
public class MyExampleClass
{
[Special(Key = "test1", Value = "1234")]
[Special(Key = "test2", Value = "4567")]
[MyAspect]
public void MyMethod()
{
MyMethod(new Dictionary<string, string>());
}
public void MyMethod(Dictionary<string, string> values)
{
//Do work
}
}
[Serializable]
public class MyAspect : MethodInterceptionAspect
{
Dictionary<string, string> values = new Dictionary<string, string>();
MethodInfo target;
public override void CompileTimeInitialize(System.Reflection.MethodBase method, AspectInfo aspectInfo)
{
target = method.DeclaringType.GetMethod(method.Name, new Type[] { typeof(Dictionary<string, string>) });
foreach (Attribute a in method.GetCustomAttributes(false))
{
if (a is SpecialAttribute)
{
values.Add(((SpecialAttribute)a).Key, ((SpecialAttribute)a).Value);
}
}
}
public override void OnInvoke(MethodInterceptionArgs args)
{
if (values == null || values.Count < 1)
{
args.Proceed();
}
else
{
target.Invoke(args.Instance, new object[] { values });
}
}
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true) ]
public class SpecialAttribute : Attribute
{
public string Key { get; set; }
public string Value { get; set; }
}
}
目标和值都在编译时(不是运行时)初始化,以便在运行时使用。它们在编译时被序列化。这样就可以节省运行时的反射效果。
答案 1 :(得分:0)
就像说明一样,我最终使用了MethodInterceptionAspect并且仅重写了OnInvoke。在OnInvoke中,我查看了args.Method.GetCustomAttributes(),给了我设置的所有System.Attributes(即DustinDavis示例中的SpecialAttribute)。
使用这些属性及其属性,我可以运行运行所需的逻辑。如果逻辑成功,我用args.Proceed()完成,如果不是,我抛出异常。