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

C# PostSharp:在目标构造函数之后初始化实例范围的方面,c#,postsharp,C#,Postsharp,我已经编写了一个方面,实现了IInstanceScopedSpect并继承了LocationInterceptionSpect 初始化时,它从目标对象读取一些属性。问题是在目标对象的构造函数运行之前调用了iInstanceScopedSpect.RuntimeInitializeInstance()。因此,目标对象没有完全初始化,读取其属性会导致各种恶劣行为 当目标对象已完全初始化(即其所有构造函数都已运行)时,如何通知我?My属性不直接应用于目标类,而是应用于其一个或多个属性。RuntimeI

我已经编写了一个方面,实现了IInstanceScopedSpect并继承了LocationInterceptionSpect

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


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

RuntimeInitializeInstance用于在PostSharp创建新实例时初始化方面。它总是在初始化类之前被调用。当您的方面是LocationInterceptionSpect时,在实例化对象时,您的方面需要做什么

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

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

查看以下有关如何执行此操作的文章:


虽然这是一个老问题,但我已经找到了一种简单的方法来确定层次结构中最顶层(最后一个)构造函数的OnExit

我要做的是将类类型存储在compile类型,然后检查活动构造函数的类类型是否与此对象的实例类型相同

在这种情况下,我们知道我们处于顶级(最后一个)构造函数中,我们可以安全地使用每个类成员,甚至是虚拟类成员

请参阅以下代码:

    [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!
            }
        }
    }
对于遇到这个问题的谷歌人(比如我)

OnInstanceConstructed建议可立即解决此问题

更新了我的答案,添加了一个示例。我相信你能从那里找到答案。回答得好。构造函数的棘手之处在于,很难定义何时在构造函数之后。可以链接多个构造函数,那么如何确定何时“完成”构造?这不是小事。理想情况下,应该在所有构造函数中添加一个深度跟踪参数。@Gael Fraiteur,我也想到了这一点,但我认为这只是必须根据具体情况处理的问题。我不太清楚他的用法是什么,所以我没有费心去解决它。当我写一个位置级方面时,我走了另一条路:我从LocationLevelAspect派生并添加了一个带有方法切入点的OnMethodEntryAdvice。非常感谢你的链接@盖尔·达斯汀达维斯:看来我遇到了你上面提到的链式构造函数问题。如果目标类型有多个构造函数相互调用,我目前无法知道最后一个构造函数何时完成。用户是否真的必须向所有构造函数引入一个深度参数(这会使方面的使用变得非常难看)?还有其他方法吗?理论上,您可以使用PostSharp自动创建带有深度参数的构造函数重载(我为客户设计了这种构造函数重载方案)。但您必须使用PostSharp SDK,而这正是我们通常开始说“这是不可能的”的地方。这完全取决于你想解决的问题的规模和你想在解决方案上投入的时间。这还不排除顶级(最后一级)中的多个构造函数。是的,史蒂文,你是对的。这个问题可以通过只为构造函数添加OnEnter逻辑来轻松处理,以便跟踪从这个类调用的第一个构造函数,它将是这个类的最顶层构造函数。在这种情况下,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!
            }
        }
    }