这部分内容没找到相关文档参考,只是结合在VS里debug结果猜想一下。
首先解决一个问题,扩展类是什么时候实例化的,这个很容易求证,用VS debug跟踪一下就知道了。
1 static public void Main(Args _args) 2 { 3 Person person = new Person(); 4 5 person.Height = 1.75; 6 person.Weight = 70; 7 8 info (num2Str(person.BMI(),0 ,2, 0, 0)); 9 Person::Introduce(); 10 }
执行到第5行,第一次引用到扩展类实例属性的时候会调用Person_Extension的new方法进行实例化。
如果最开始不调用实例属性,直接调用Person_Extension的实例方法会进行实例化吗?
1 static public void Main(Args _args) 2 { 3 Person person = new Person(); 4 5 person.Stage(); 6 7 person.Height = 1.75; 8 person.Weight = 70; 9 10 info (num2Str(person.BMI(),0 ,2, 0, 0)); 11 Person::Introduce(); 12 }
执行到第5行调用Stage这个实例方法的时候,并不会调用Person_Extension的new方法进行实例化。
也就是说Person这个实例对象在调用Person_Extension的实例方法的时候,Person_Extension还没实例化,正常情况下如果对象没有实例化就调用它的实例方法,会报错的。
跟踪进Stage方法,用变量跟踪查看this
VS给出的提示是this在静态方法中无效,所以这个Stage方法虽然签名是个实例方法,但是可能只是个语法糖,实质上跟C#的扩展方法一样,是个静态方法,只不过被X++封装成了个实例方法,这样语义上好理解。
在监视器里看到一个@this的变量,它的构成是Person的类变量 + Person_Extension。
由此猜想,它的实现是不是这样:
系统在底层构造了一个对象,这个对象存放被扩展类和扩展类,就是存放了Person及其扩展类,比如Person_Extension,为了验证这个说法,再创建一个Person的扩展类Person_Another_Extension,可以看到@this里多了一个变量。
实例化后的对象person在调用扩展类的方法时,实际上是按照C#扩展方法的方式调用的,Person_Extension的实例方法,比如Stage,实际上是静态方法,person对象在调用stage的时候,把指向person对象的引用作为方法的第一个参数隐形传给了该方法,这样才能解释为什么在Person_Extension未实例化的情况下还可以调用实例Stage方法,以及在变量追踪的时候,查看this变量会提示this在静态方法中无效。
Person_Extension实例化出来只是为了存放扩展的实例属性的值,如测试例子中的Height和Weight,只有调用到实例属性的时候才会实例化扩展类,如果扩展类没有包含实例属性,可能都扩展类都不会被实例化。
以上纯属猜想,我们使用X++的扩展类时把它当做一般的类来使用理解它的语义就可以了,至于底层的实现猜想一下只是为了满足好奇心。
D365F&O的扩展类学习到此结束。