PostSharp:在目标构造函数之后初始化实例范围的方面

时间:2011-07-29 12:26:47

标签: c# postsharp

我编写了一个实现IInstanceScopedAspect并从LocationInterceptionAspect继承的方面。

初始化时,它会从目标对象中读取一些属性。问题是在目标对象的构造函数运行之前调用IInstanceScopedAspect.RuntimeInitializeInstance()。所以目标对象没有完全初始化,读取它的属性会导致各种令人讨厌的行为。

如何在目标对象完全初始化(即所有构造函数都已运行)时收到通知?我的属性不是直接应用于目标类,而是应用于其一个或多个属性。

3 个答案:

答案 0 :(得分:4)

RuntimeInitializeInstance用于在PostSharp创建新实例时初始化您的方面。在你的课程初始化之前,它总会被调用。当您的方面是位置拦截时,您在实例化对象时需要做什么?

我建议创建一个复杂的方面,其中包含一个针对构造函数的OnExit建议,这个建议将在任何构造函数运行后运行。在OnExit建议中,完成您需要的工作。那时你的对象将被初始化。

因此,您的复杂方面将包括您的位置拦截建议和其他OnMethodExitAdvice。

查看这些文章,了解如何执行此操作:

http://www.sharpcrafters.com/blog/post/PostSharp-Principals-Day-12-e28093-Aspect-Providers-e28093-Part-1.aspx

http://www.sharpcrafters.com/blog/post/PostSharp-Principals-Day-13-e28093-Aspect-Providers-e28093-Part-2.aspx

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