我编写了一个实现IInstanceScopedAspect
并从LocationInterceptionAspect继承的方面。
初始化时,它会从目标对象中读取一些属性。问题是在目标对象的构造函数运行之前调用IInstanceScopedAspect.RuntimeInitializeInstance()
。所以目标对象没有完全初始化,读取它的属性会导致各种令人讨厌的行为。
如何在目标对象完全初始化(即所有构造函数都已运行)时收到通知?我的属性不是直接应用于目标类,而是应用于其一个或多个属性。
答案 0 :(得分:4)
RuntimeInitializeInstance用于在PostSharp创建新实例时初始化您的方面。在你的课程初始化之前,它总会被调用。当您的方面是位置拦截时,您在实例化对象时需要做什么?
我建议创建一个复杂的方面,其中包含一个针对构造函数的OnExit建议,这个建议将在任何构造函数运行后运行。在OnExit建议中,完成您需要的工作。那时你的对象将被初始化。
因此,您的复杂方面将包括您的位置拦截建议和其他OnMethodExitAdvice。
查看这些文章,了解如何执行此操作:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
ExampleClass ec = new ExampleClass();
ec.ID = 10;
Console.ReadKey();
}
}
[ComplexAspect]
class ExampleClass
{
public int ID { get; set; }
public string Name { get; set; }
public ExampleClass()
{
//Setup
Name = "John Smith";
}
}
[Serializable]
public class ComplexAspect : InstanceLevelAspect
{
[OnMethodExitAdvice, MulticastPointcut(MemberName=".ctor")]
public void OnExit(MethodExecutionArgs args)
{
//Object should be initialized, do work.
string value = ((ExampleClass)args.Instance).Name;
Console.WriteLine("Name is " + value);
}
[OnLocationGetValueAdvice, MulticastPointcut(Targets=MulticastTargets.Property )]
public void OnGetValue(LocationInterceptionArgs args)
{
Console.WriteLine("Get value for " + args.LocationName);
args.ProceedGetValue();
}
[OnLocationSetValueAdvice, MulticastPointcut(Targets = MulticastTargets.Property)]
public void OnSetValue(LocationInterceptionArgs args)
{
Console.WriteLine("Set value for " + args.LocationName);
args.ProceedSetValue();
}
public override void RuntimeInitializeInstance()
{
base.RuntimeInitializeInstance();
}
}
}
答案 1 :(得分:2)
虽然这是一个老问题,但我已经想出了一种简单的方法来识别层次结构中顶级(最后)构造函数的OnExit 。
我所做的是将类类型存储在编译类型中,然后检查活动构造函数的类类型是否与此对象的实例类型相同。
在这种情况下,我们知道我们在顶级(最后)构造函数中,我们可以安全地使用每个类成员,甚至是虚拟成员。
请参阅以下代码:
[Serializable]
[MulticastAttributeUsage(MulticastTargets.Class, AllowMultiple=false, Inheritance = MulticastInheritance.Multicast)]
public class PostConstructorAttribute : InstanceLevelAspect {
private Type _classType;
public override void CompileTimeInitialize(Type type, AspectInfo aspectInfo) {
//Assign the class type to the _classType variable,
//At compile time this will always be the type of the class we are currently in.
_classType = type;
base.CompileTimeInitialize(type, aspectInfo);
}
[OnMethodExitAdvice, MulticastPointcut(MemberName = ".ctor")]
public void OnExit(MethodExecutionArgs args)
{
//Instance is the top most type of the hierarchy,
//so if _classType is the top most type then we are in the top most constructor!
if (Instance.GetType() == _classType) {
//We are at the top most constructor and after all constructors have been called.
//Everything is setted up now and we can safely use virtual functions
//Magic happens here!
}
}
}
答案 2 :(得分:1)
对于遇到此问题的googlers(像我一样)
OnInstanceConstructed Advice解决了这个问题 http://doc.postsharp.net/t_postsharp_aspects_advices_oninstanceconstructedadvice