Showing posts with label container. Show all posts
Showing posts with label container. Show all posts

Monday, July 7, 2025

Packing Sets, Maps, Lists, etc. in D365FO: Why con2str can break your code

While working on what seemed like a routine task in Dynamics 365 Finance and Operations, I encountered an unexpected issue Specified cast is not valid when passing a Set as a parameter to a method. 


Here's what happened.

I had a simple and logical flow:

1. Pack a set or a list into a container with standard pack method.



2. Convert this container into a string with con2str global function.


3. Pass it to my function as an argument. (not depicted)

4. Convert this string back to a container via str2con.



5. Create a new set from the restored container via set create method.

Everything worked fine—until step 5.

Instead of a smooth reconstruction of the Set, I ran into an error. The root cause? The str2con() function. By default, str2con() interprets numeric values as Int64 (long integers). This silent type coercion corrupted the data structure expected by Set.create(), which led to the failure.


To avoid this issue altogether, do not use str2con() to restore containers that will be used for object reconstruction (like sets, maps, etc.). Instead, use:

  • con2base64str() to serialize the container

  • base64str2con() to safely deserialize it

These Global functions preserve the data types and internal structure of the container without any implicit type conversions.

Saturday, December 11, 2021

Supporting functions to work with multiple selection of Enum values

There a couple of custom static methods you can use to facilitate your job with Enum values in tables and forms.

class wzhTest
{
    public const str contSeparator = ';';
    /// <summary>
    /// Populates a map for all enum's values
    /// </summary>
    /// <param name = "_enumName">Enum name</param>
    /// <returns>Map object</returns>
    public static Map createMapForEnum(EnumName _enumName)
    {
        Map             map          = new Map(Types::Enum, Types::String);
        DictEnum        dictEnum = new DictEnum(enumName2Id(_enumName));
        for(int i = 0; i < dictEnum.values(); i++)
        {
            map.insert(dictEnum.index2Value(i), dictEnum.index2Symbol(i));
        }
        return map;
    }
    /// <summary>
    /// Creates a container with enum values from a given string values container
    /// </summary>
    /// <param name = "_cont">string values container</param>
    /// <param name = "_enumType">enum variable for defining its type</param>
    /// <returns>Container with enum value</returns>
    public static container enumValuesCont2EnumStrCont(container _cont, int _enumId)
    {
        container       ret;
        str             s;
        int             idx = 0;
        int             len = conLen(_cont);
        while (idx < len)
        {
            idx += 1;
            s           = conPeek(_cont, idx);
            if(s)
            {
                ret += enum2Symbol(_enumId, conPeek(_cont, idx));
            }
        }
        return ret;
    }

    /// <summary>
    /// Creates a string with enum values string
    /// </summary>
    /// <param name = "_s">string values separated with ; sign</param>
    /// <param name = "_enumType">enum variable for defining its type</param>
    /// <returns>String with enum values separated with ; sign</returns>
    public static str enumValuesStr2EnumStrStr(str _s, int _enumId)
    {
        container c = str2con(_s, wzhTest::contSeparator);
        c = wzhTest::enumValuesCont2EnumStrCont(c, _enumId);
        return con2Str(c, wzhTest::ContSeparator);
    }
}

Let's see how they work with AccessControlledType enum type.

 static public void main(Args _args)
    {
        AccessControlledType enumEDT;
        //AccessControlledType::MenuItemDisplay / 0
        //AccessControlledType::MenuItemOutput / 1
        //AccessControlledType::MenuItemAction /2
        //AccessControlledType::WebUrlItem /3
        //AccessControlledType::WebActionItem /4
        //AccessControlledType::WebManagedContentItem / 5
        //AccessControlledType::Table / 6
        // AccessControlledType::TableField / 7
        EnumId      id      = enumName2Id(enumStr(AccessControlledType));
        str         name    = enumId2Name(id); //enumStr(AccessControlledType)

Basically, they convert a enum values list from string and vice-versa by using standard functions.

Check the output of each static method.

        //createMapForEnum
        Info("Test createMapForEnum");
        Info(strFmt("%1 : %2 values", id, name));
        Map         m = wzhTest::createMapForEnum(name);
        MapIterator mi = new MapIterator(m);
        int i;
        while(mi.more())
        {
            Info(strFmt("%1 : '%2'", i, mi.value()));
            mi.next();
            i++;
        }


        //enumValuesCont2EnumStrCont
        Info("Test enumValuesCont2EnumStrCont");
        setPrefix('');
        container   c1 = [AccessControlledType::WebActionItem, AccessControlledType::MenuItemOutput];
        container   c2 = wzhTest::enumValuesCont2EnumStrCont(c1, id);

        for(i=1;i<=conLen(c2);i++)
        {
            Info(strFmt("%1 => '%2'", conPeek(c1,i), conPeek(c2,i)));
        }


        //enumValuesStr2EnumStrStr
        Info("Test enumValuesStr2EnumStrStr");
        str         s1 = con2Str([AccessControlledType::Table, AccessControlledType::TableField], wzhTest::contSeparator);
        str         s2 = wzhTest::enumValuesStr2EnumStrStr(s1, id);
        Info(strFmt("'%1' => '%2'", s1, s2));