PostSharp:在目标构造函数之后初始化实例作用域的方面

本文关键字:实例 作用域 方面 初始化 之后 目标 构造函数 PostSharp | 更新日期: 2023-09-27 18:04:09

我已经写了一个方面实现IInstanceScopedAspect和继承LocationInterceptionAspect。

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

当目标对象已经完全初始化(也就是说,它的所有构造函数已经运行)时,我如何得到通知?我的属性不是直接应用于目标类,而是应用于它的一个或多个属性。

PostSharp:在目标构造函数之后初始化实例作用域的方面

RuntimeInitializeInstance意味着在PostSharp创建一个新实例时初始化你的方面。它总是在你的类初始化之前被调用。当你的方面是一个locationinterceptionaspect时,你的方面在对象的实例化点需要做什么?

我建议创建一个复杂的方面,包括一个OnExit通知,目标是构造函数,这个通知将在任何构造函数运行后运行。在OnExit建议中,做你需要做的工作。到那时你的对象将被初始化。

所以你的复杂方面将包括你的locationinterception建议和一个额外的OnMethodExitAdvice。

查看这些关于如何做到这一点的文章:

http://www.sharpcrafters.com/blog/post/postsharp -主体-天- 12 - e28093方面-供应商- e28093部分- 1. - aspx

http://www.sharpcrafters.com/blog/post/postsharp主体-天- 13 - e28093方面-供应商- e28093 - - 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();
        }
    }
}

虽然这是一个老问题,但我已经找到了一种简单的方法来识别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!
            }
        }
    }

对于遇到这个问题的google用户(像我一样)

OnInstanceConstructed Advice立即解决了这个问题http://doc.postsharp.net/t_postsharp_aspects_advices_oninstanceconstructedadvice