zoukankan      html  css  js  c++  java
  • [AX]AX2012 使用.NET Interop from X++

    已经讲过可以通过Proxy class从C#使用X++的类,反过来从X++使用CLR的类型当然也是可以的,这在以前版本的AXAPTA 4.0、AX 2009就开始支持了,这里把要注意的问题做一简单的归纳。

    X++使用CLR类的静态方法需要使用“::”而不是C#中的“.”,这和X++调用X++类的静态方法是一样的:

    System.String netString=System.Convert::ToString("xxx");

    从X++的数据类型到CLR的元类型或者从CLR的元类型到X++的数据类型,会自动进行隐式的marshal转化,下表是两者类型的对应关系:

    X++ type

    CLR type

    boolean

    System.Boolean

    date

    System.DateTime

    int

    System.Int32

    int64

    System.Int64

    str

    System.String

    guid

    System.Guid

    Real

    System.Single or System.Double

    X++的int类型是不会转化成CLR的Int64的,CLR的Int32也是不会转成X++的int64,反过来从64位到32位整数也是一样。X++的real类型同时对应CLR的Single和Double两种,X++的real类型可以直接赋值给CLR的Single类型,在AX2009中也可以直接赋值给Double类型,但是以后的版本中可能会改变,AX2012提供函数Global::real2double(xppReal)将X++的real类型转成CLR的Double类型。

    X++ timeofday没有对应的CLR元类型,它内部其实使用整数类型来表示数据的。同样X++的utcdatetime也没有对应的CLR类型,AX2012提供Global::utcDateTime2SystemDateTime()和Global::CLRSystemDateTime2UtcDateTime()两个方法来相互转换。AX2012还提供DateTimeUtil::tostr()从utcdatetime转换成字符串,和DateTimeUtil::parse()从字符串转换成utcdatetime,需要注意的是CLR的System.Convert.ToString()或者System.DateTime.ToString()得到字符串是不能直接被DateTimeUtil::parse()解析的,时间字符串的格式要使用ISO的标准24小时格式“yyyy-mm-ddThh:mm:ss”,比如当前的时间应该为“2012-09-11T10:01:05”,实际上这样的格式的时间是可以直接赋值给X++的utcdatetime而不需要DateTimeUtil::parse()做额外的转换,比如:

    utcdatetime  xppIsoDttm = 2012-09-11T10:01:05;

    在X++中CLR的值类型实际上是以引用保存的,这意味着除了“=”赋值操作符外,不能使用“==”或者“>”等逻辑运算符来比较两个CLR值类型,也不能使用位操作符“&”及“|”。比如两个System.Int32的变量a和b,这样判断“a>=b”是不正确的,相应的要使用System.Int32.CompareTo()方法。

    X++可以使用CLR的数组,同样使用“[]”定义一个数组,内部创建System.Array的CLR类型,但是不能使用“[]”访问CLR数组的元素,而要使用GetValue()、SetValue()等方法:

    static void JobTestNetArray()
    {
        System.Int32[] iNetNumbers; // .NET Framework array
        int iXppNumbers[2]; // X++ array
        int iXppNum,iXppArrayLength,i;
        ;
        info("Next, .NET Framework array by special X++ syntax.");
        //-------- .NET Framework array by special X++ syntax ------
        iNetNumbers = new System.Int32[2](); // Note the () at end.
        iNetNumbers.SetValue(100, 0); // Resembles iNetNumbers[0]=100.
        iNetNumbers.SetValue(101, 1);
        
        iXppArrayLength = iNetNumbers.get_Length();
        for (i = 0; i < iXppArrayLength; i++)
        {
            iXppNum = iNetNumbers.GetValue(i); // Resembles iNetNumbers[i].
            info(int2str(iXppNum));
        }
    
        info("Next, X++ Native array.");
        //----------- X++ Native array ------
        iXppNumbers[1] = 2201;
        iXppNumbers[2] = 2202;
    
        for (i = 1; i <= dimOf(iXppNumbers); i++)
        {
            info(int2str(iXppNumbers[i]));
        }
    
    }

    X++数组和CLR数组有很多的不同:X++数组下标从1开始,CLR数组下标从0开始;X++数组定义了就可以使用,CLR数组必须使用new关键字构建;X++数组索引必须是X++的整数类型,CLR数组索引则可以是CLR的整数类型,也可以是X++的整数类型;X++数组是一维的,CLR数组可以是多维的;X++的数组元素只能是str或者int类型,CLR数组元素则可以是任何CLR类型,但不能是X++的类型;X++数组的长度在定义时就确定了,CLR数组的类型在new时确定,new时必须指定数组长度,否则报语法错不能编译。

    X++的类型可以作为函数参数传递给CLR的函数,比如CLR函数参数原型为System.String,可以将X++的str传递给这个函数,但是反过来是不可以的,不能把CLR的类型传递给需要X++类型参数的函数。对于C# ref、out标识的引用参数,X++提供byref关键字表示引用参数传递。需要注意的是那种值传递的对象类型,在传递给被调用函数前会将对象类型的指针复制一份传递,看这样一个例子:

     class MyClass //X++
        {
    
            public static void CallerMethodByValueObject() // X++
            {
                TestProxyClass.MyEntity meTest1;
                TestProxyClass.MyEntity meTest2;
                int i;
    
                ;
                meTest1 = new TestProxyClass.MyEntity(1);
                meTest2 = new TestProxyClass.MyEntity(33);
                MyClass::CalledMethodByValueObject(meTest1, meTest2);
        
                i=meTest1.GetCounter();
                if (i == 1)
                {
                    info("Good, == 1");
                }
                i=meTest2.GetCounter();
                if (i == 36)
                {
                    info("Good, == 36");
                }
        
                TestProxyClass.MyEntity::CalledMethodByValueObject(meTest1,meTest2); //X++
                i=meTest1.GetCounter();
                if (i == 1)
                {
                    info("Good, == 1");
                }
                i=meTest2.GetCounter();
                if (i == 39)
                {
                    info("Good, == 39");
                }
        
            }
    
            static public void CalledMethodByValueObject // X++
                    (
                     TestProxyClass.MyEntity meTest1  // by value
                    , TestProxyClass.MyEntity meTest2 // by value
                    )
            {
                ;
                meTest1 = new TestProxyClass.MyEntity(555); // Caller can not detect.
                meTest2.AddToCounter(3); // Caller can detect.
            }
    
    
        }
    
    
    public class MyEntity //C#
        {
            private int _counter;
    
            public MyEntity(int counter)
            {
                _counter = counter;
            }
    
            public int GetCounter() { return _counter; }
            public void AddToCounter(int c)
            {
                _counter += c;
            }
    
            static public void CalledMethodByValueObject 
            (
            MyEntity meTest1  // by value
            , MyEntity meTest2 // by value
            )
            {
                ;
                meTest1 = new MyEntity(555); // Caller can not detect.
                meTest2.AddToCounter(3); // Caller can detect.
            }
        }

    MyEntity是一个C#的类,在X++的MyClass::CallerMethodByValueObject()方法中以值的方式分别传递meTest1、meTest2给X++的MyClass::CalledMethodByValueObject和C#的MyEntity.CalledMethodByValueObject两个静态方法,主程序中显示meTest1的结果都是1,这说明被调用函数中修改的meTest1只是传入变量指针的拷贝,不会影响到主程序中的变量,不管是被调用函数是X++还是C#都是一样,其实在C#中调用MyEntity.CalledMethodByValueObject也是得到相同的结果,这点上X++和C#是一致的。

    X++使用的CLR程序集要么是在AOT的Reference节点下手工引用,或者是在GAC,在客户端AX会提示把引用的程序集放到client的bin目录下,默认C:\Program Files (x86)\Microsoft Dynamics AX\60\Client\Bin,服务端是在C:\Program Files\Microsoft Dynamics AX\60\Server\MicrosoftDynamicsAX\bin,注意和我们把c# project添加到AOT后的部署路径是不同的。虽然可以使用server关键字让类的静态方法在AOS运行,但是试图从这些server方法返回一个CLR对象到client是不可以的,收到的结果是CLRojbect未初始化异常。

    X++可以使用try...catch捕捉CLR异常,提供了专门的异常类型Exception::CLRError,在捕捉到CLR异常后可以使用ClrInterop::getLastException()获得一个CLR的异常对象System.Exception,调用它的get_InnerException()可以进一步获得此异常的详细信息。

    X++的系统类DictMethod提供方法clrParameterType、clrReturnType、clrVarType来获取X++方法的参数CLR类型、函数返回值CLR类型和函数本地变量CLR类型。

    更多有关.NET Interop from X++的内容见http://msdn.microsoft.com/en-us/library/cc598160

  • 相关阅读:
    mongodb分片
    mongodb读写分离的一些选项的理解
    mongodb管理副本集(持续更新中)
    mongodb配置副本集(多台服务器间的副本集搭建) replica[ˈrɛplɪkə]
    mongodb副本集的基础概念和各种机制
    mongodb的查询
    mongodb文档的CRUD
    SQLServer2008数据库连接error40错误
    Did you forget about DBModel.InitializeModel the model [AAAdm] ?
    ERP中通过EDI导入资料的时候出现【Microsoft Office Excel不能访问文件‘C:WindowsTEMP433....’
  • 原文地址:https://www.cnblogs.com/duanshuiliu/p/2682832.html
Copyright © 2011-2022 走看看