How to: Marshal Between X++ and CLR Primitive Types

In Microsoft Dynamics AX, the X++ language does implicit conversion or marshaling between several X++ primitive types and their counterpart types managed by the common language runtime (CLR). This means that the X++ assignment operator, the single equal sign (=), can be used between certain pairings of an X++ type with a CLR type.

Implicit marshaling with the X++ assignment operator works in both directions, either from X++ types to CLR types, or from CLR to X++.

Why Marshaling is Useful

A .NET managed assembly might provide a useful method that returns a System.String object. You can call the method and capture the returned System.String in a variable of that type that you declare in your X++ code.

But if your next step is to pass that string into an X++ method that takes a str, you must first marshal the System.String into a str.

For more information, see How to: Substitute Primitive Parameter Types Between the CLR and X++.

Implicitly Marshaled Conversion Pairs

Each row in the following table lists a pairing of types that are implicitly marshaled by the X++ assignment operator.

Note

There is no implicit marshaling between the X++ utcdatetime and .NET Framework System.DateTime type. For more information about how to convert between utcdatetime and System.DateTime, see How to: Convert Between utcdatetime and System.DateTime.


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

Code Sample for System.Boolean

The following code sample shows the marshaling between the .NET Framework System.Boolean type and its X++ counterpart boolean.

static void JobBooleanMarshal(Args _args) // X++ job.
{
    System.Boolean netBool; // .NET
    boolean xppBool; // X++
    ;
    // Marshal .NET to X++.
    xppBool = false;

    netBool = true;
    xppBool = netBool; // Marshals.
    if (true == xppBool)
    {
        info("A1. Good, .NET was marshaled to X++.");
    }
    else
    {
        info("A2. Bad, .NET was not marshaled to X++.");
    }
    // Marshal X++ to .NET.
    netBool = true;
    
    xppBool = false;
    netBool = xppBool; // Marshals.
    
    xppBool = true;
    xppBool = netBool;
    if (false == xppBool)
    {
        info("B1. Good, X++ was marshaled to .NET.");
    }
    else
    {
        info("B2. Bad, X++ was not marshaled to .NET.");
    }
}
/***** Actual infolog output
Message (01:08:32 pm)
A1. Good, .NET was marshaled to X++.
B1. Good, X++ was marshaled to .NET.
*****/

Code Sample for System.DateTime

The following code sample shows the marshaling between the .NET Framework System.DateTime type and the X++ date type. From System.DateTime, there is no marshaling to the X++ utcdatetime type. And there is no marshaling from System.DateTime to the timeOfDay extended data type (which is an int).

static void JobDateTimeMarshal(Args _args)
{
    System.DateTime netDttm;
    date xppDate;
    str strTemp;
    ;
    // Marshal .NET to X++.
    netDttm = new System.DateTime(1988,7,20 ,13,44,55);
    xppDate = netDttm; // Marshals.
    if (date2str(xppDate,321, 2,2,2,2,4) == "1988.07.20")
    {
        info("A1. Good, .NET was marshaled to X++.");
    }
    else
    {
        info("A2. Bad, .NET was not marshaled to X++.");
    }
    // Marshal X++ to .NET.
    xppDate = 25\11\2002;
    netDttm = xppDate; // Marshals.
    strTemp = netDttm.ToString("s");
    if (strTemp == "2002-11-25T00:00:00")
    {
        info("B1. Good, X++ was marshaled to .NET.");
    }
    else
    {
        info("B2. Bad, X++ was not marshaled to .NET.");
    }
}

Code Sample for System.Int32

The following code sample shows the marshaling between the .NET Framework System.Int32 type and its X++ counterpart int.

static void JobInt32Marshal(Args _args)
{
    System.Int32 netInt;
    int xppInt;
    ;
    // Marshal .NET to X++.
    netInt = 33;
    xppInt = netInt; // Marshals.
    if (33 == xppInt)
    {
        info("A1. Good, .NET was marshaled to X++.");
    }
    else
    {
        info("A2. Bad, .NET was not marshaled to X++.");
    }
    // Marshal X++ to .NET.
    netInt = 0;

    xppInt = 444;
    netInt = xppInt; // Marshals.

    xppInt = 0;
    xppInt = netInt;
    if (444 == xppInt)
    {
        info("B1. Good, X++ was marshaled to .NET.");
    }
    else
    {
        info("B2. Bad, X++ was not marshaled to .NET.");
    }
}

X++ int Does Not Marshal to System.Int64

Automatic marshaling works between the X++ int64 type and the .NET Framework type System.Int64, just as marshaling works between the X++ int and the .NET System.Int32.

An X++ int does not marshal to a System.Int64, nor the reverse. A System.Int32 does not marshal to an X++ int64, nor the reverse.

Code Sample for System.String

The following code sample shows the marshaling between the .NET Framework System.String type and its X++ counterpart str.

static void JobStringMarshal(Args _args)
{
    System.String netString;
    str xppString;
    ;
    // Marshal .NET to X++.
    netString = "cat";
    xppString = netString; // Marshals.
    if ("cat" == xppString)
    {
        info("A1. Good, .NET was marshaled to X++.");
    }
    else
    {
        info("A2. Bad, .NET was not marshaled to X++.");
    }
    // Marshal X++ to .NET.
    netString = "";

    xppString = "dog";
    netString = xppString; // Marshals.

    xppString = "";
    xppString = netString;
    if ("dog" == xppString)
    {
        info("B1. Good, X++ was marshaled to .NET.");
    }
    else
    {
        info("B2. Bad, X++ was not marshaled to .NET.");
    }

/***** Actual infolog output
Message (06:27:19 am)
A1. Good, .NET was marshaled to X++.
B1. Good, X++ was marshaled to .NET.
*****/
}

Code Sample for System.Guid

The following code sample shows the marshaling between the .NET Framework System.Guid type and its X++ counterpart guid.

static void JobGuidMarshal(Args _args)
{
    System.Guid netGuid;
    guid xppGuid;
    str sGuid1
        ,sGuid2;
    ;
    sGuid1 = "10001000-1000-1000-1000-100010001000";
    sGuid2 = "20002000-2000-2000-2000-200020002000";
    // Marshal .NET to X++.
    netGuid = Global::guidFromString(sGuid1);
    xppGuid = netGuid; // Marshals.
    if (xppGuid == Global::guidFromString(sGuid1))
    {
        info("A1. Good, .NET was marshaled to X++.");
    }
    else
    {
        info("A2. Bad, .NET was not marshaled to X++.");
    }
    // Marshal X++ to .NET.
    xppGuid = Global::guidFromString(sGuid2);
    netGuid = xppGuid; // Marshals.
    xppGuid = Global::guidFromString(sGuid1);
    xppGuid = netGuid;
    if (xppGuid == Global::guidFromString(sGuid2))
    {
        info("B1. Good, X++ was marshaled to .NET.");
    }
    else
    {
        info("B2. Bad, X++ was not marshaled to .NET.");
    }
}

Code Sample for System.Single and System.Double

The following code sample shows the marshaling between the .NET Framework types System.Single and System.Double, and their mutual X++ counterpart real. The sample shows that the X++ real does marshal in both directions, with both .NET Framework types.

static void JobRealMarshal(Args _args)
{
    str xppStr;
    real xppReal;
    System.Double netDouble;
    System.Single netSingle;
    ;
    xppReal = 1.2305e+6;

    netSingle = xppReal;
    xppReal = 0.0;
    xppReal = netSingle;

    netDouble = xppReal;
    xppReal = 0.0;
    xppReal = netDouble;

    netSingle = xppReal;
    xppStr = System.Convert::ToString(netSingle);
    info(xppStr);
}
/***** Actual infolog output
Message (01:39:56 pm)
1230500
*****/

Operator Limitations

When you work with .NET primitive types in X++ code, you can use the X++ equal sign (=) assignment operator. However, no other operators can be used with CLR primitives. For instance, you cannot use the comparison operators (such as == or >). Also, you cannot use bitwise operators (such as & or |).

For more information about X++ operators with .NET primitive types, see Operators for CLR Primitive Types.

See Also

.NET CLR Interop Overview