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

发布于 2024-11-27 02:53:14 字数 289 浏览 2 评论 0 原文

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

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

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

I have written an aspect implementing IInstanceScopedAspect and inheriting from LocationInterceptionAspect.

When initialized, it reads some properties from the target object. The problem is that IInstanceScopedAspect.RuntimeInitializeInstance() is called before the target object's constructors have run. So the target object is not fully initialized and reading its properties leads to all kinds of nasty behavior.

How can I be notified when the target object has been fully initialized (that is, all its constructors have run)? My attribute is not applied directly to the target class but to one or more of its properties.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

榕城若虚 2024-12-04 02:53:14

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();
        }

    }
}

The RuntimeInitializeInstance is meant to initialize your aspect when PostSharp creates a new instance. It's going to always be called before your class is initialized. What exactly is your aspect needing to do at the point of instantiation of the object when your aspect is a locationinterceptionaspect?

I suggest creating a complex aspect that includes an OnExit advice that targets constructors and this advice will be run after any constructor runs. In the OnExit advice, do the work you need there. your object will be initialized by then.

So your complex aspect would include your locationinterception advices and an additional OnMethodExitAdvice.

Check out these articles on how to do this:

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();
        }

    }
}
余罪 2024-12-04 02:53:14

虽然这是一个老问题,但我已经找到了一种简单的方法来识别层次结构中顶部(最后一个)构造函数的 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!
            }
        }
    }

Although this is an old question, I have figured out an easy way to identify the OnExit for the top (last) constructor in a hierarchy.

What I do is store the class type at compile type and then check if the class type of the active constructor is the same as the Instance type of this object.

In that case we know we are in the top (last) constructor and we can safely use every class member, even virtual ones.

Please see the following code:

    [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!
            }
        }
    }
枉心 2024-12-04 02:53:14

对于遇到此问题的 Google 用户(像我一样),

OnInstanceConstructed Advice 开箱即用地解决了此问题
http://doc.postsharp.net/t_postsharp_aspects_advices_oninstanceconstructedadvice

For the googlers (like me) who run into this issue

the OnInstanceConstructed Advice solves this problem out of the box
http://doc.postsharp.net/t_postsharp_aspects_advices_oninstanceconstructedadvice

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文