Serializace výčtových typů

Situace: Webová služba hostovaná na AOS Dynamics AX 2012, na požádání najde určitá data v databázi a vrátí je. Typ jednoho z polí je výčtový typ UtilElementType.

Problém: Není-li nalezen žádný záznam, systém vyhodí výjimku “Enum value ‘0’ is invalid for type ‘Dynamics.Ax.Application.UtilElementType’ and cannot be serialized.” (“Hodnota ‘0’ není platná pro výčtový typ ‘Dynamics.Ax.Application.UtilElementType’ a nemůže být serializována.”)

Analýza: Text výjimky naštěstí zcela přesně popisuje problém. V poli je výchozí hodnota (0), která ale vůbec není platnou hodnotou výčtu UtilElementType (nejnižší platná hodnota je 1 – DisplayTool). Tohle v zásadě nevadí ani X++ ani C# (nevím jak jiným .NET jazykům), ale serializer je v tomto striktnější.

Řešení: Nejlepším řešením by bylo použít nulovatelný (nullable) typ, což by umožnilo reprezentovat prázdnou hodnotu jednoduše jako null.

To bohužel X++ přímo nepodporuje. Nicméně si můžete udělat vlastní nulovatelný typ. To v zásadě znamená jen obalit výčtový typ do objektu, takže může mít hodnotu null. A samozřejmě, aby mohl být serializován pro přenos, musí také obsahovat přílušné atributy. Například:

[DataContractAttribute]
class UtilElementTypeNullable
{
    UtilElementType value;
 
    public new (UtilElementType _value)
    {
        value = _value;
    }
 
    [DataMemberAttribute]
    public UtilElementType value(UtilElementType _value = value)
    {
        value = _value;
        return value;
    }
}

V X++ se pak přiřadí buď null (je-li hodnota výčtu 0) nebo příslušná hodnota zabalená do nulovatelného typu:

contract.elementType(elementType == 0 ? null : new UtilElementTypeNullable(elementType));

Protože X++ nepodporuje generické typy, nelze vytvořit něco jako univerzální Nullable<T>. Je nutné buďto vytvořit vlastní třídu pro každý enum, který má být nulovatelný (což by neměl být takový problém, protože řada výčtů toto řešení nevyžaduje), nebo zcela univerzální třídu obsahující číselnou hodnotu a ID typu (pak by ale nebyl použitý výčtový typ automaticky serializován).

Poslední možností je zkrátka vždy přiřazovat platnou hodnotu. Mnoho výčtových typů přímo používá nějaký element reprezentující prázdnou hodnotu, typicky “None” s indexem 0. Jindy je možné najít jinou hodnotu hodnotu, která se normálně nepoužívá, a tu zpracovávat speciálním způsobem. Například pro UtilElementType by přicházela v úvahu hodnota RESERVED33.