Pack and
unpack is Dynamics language for serialization -- putting object-specific
data in a writeable format and later reading it back to create an
object in the exact same state.
Most of the interactive objects in Dynamics will automatically check for saved user data when invoked and instantiate accordingly. Perhaps you remember running a report and the next time you opened the report your previous query and parameter values were already there. This happens because of pack and unpack.
The majority of what makes pack and unpack confusing is macros, so let's do a simple example not using macros at all. Let's say we have a class that has two date values I need to persist between runs: startDate and endDate.
So when pack() gets called, I need to store both variables. (If you don't understand the way containers work, look them up on MSDN first, otherwise this won't make sense).
container pack()
{ return [startDate, endDate];
}
The framework will take whatever pack returns and store it in user data. So when the object is instantiated, unpack() gets called in order to reinitialize the values.
boolean unpack(container _packedValues)
{
[startDate, endDate] = _packedValues;
return true;
}
Follow what's happening here? We expect _packedValues to contain startDate and endDate in that order, so we assign those values to our class variables.
Now let's imagine we want to add another class variable that needs to be stored: isPosted
To do this, we'll have to modify our pack to return
[startDate, endDate, isPosted]
and our unpack to assign all three:
[startDate, endDate, isPosted] = _packedValues;
Hm, but what about values that were stored before our modification? That container assignment won't work because _packedValues will only contain 2 values (startDate and endDate). So let's make the first value in our packed data identify the version of the packed data so we can handle old values without crashing.
container pack()
{ return [1, startDate, endDate, isPosted];}
boolean unpack(container _packedValues)
{
boolean ret = true;
int version;
;
if (conpeek(_packedValues) == 1)
{
[version, startDate, endDate, isPosted] = _packedValues;
} else
{
ret = false;
}
return ret;}
Ok, so now if I need to add more variables, I need to change the version number in both pack and unpack, but now old data will make unpack() return false, which will initialize the parameter defaults.
So now let's add some macros so we only have to change one spot when we change what we want to pack. In our classDeclaration, we'll create 2 macros: one for the version of the data, and one for the values we wish to store.
classDeclaration()
{
#define.CurrentVersion(1)
#localMacro.CurrentList
startDate, endDate,
isPosted #endMacro }
If you're unfamiliar with macros, what they do is fill in exactly what the macro says at compile time. So whenever you write #CurrentVersion, the compiler fills in '1'. Whenever you write #CurrentList, the compiler fills in 'startDate, endDate, isPosted'. So now we can change our pack() and unpack() to look like this:
container pack()
{
return [#CurrentVersion, #CurrentList];
}
boolean unpack(container _packedValues)
{
int version; boolean ret = true;
;
if (conpeek(_packedValues) == #CurrentVersion)
{ [version, #CurrentList] = _packedValues;
}
else
{ ret = false; }
return ret;
}
Note:Copied from https://community.dynamics.com/ax/f/33/p/67248/122709
Most of the interactive objects in Dynamics will automatically check for saved user data when invoked and instantiate accordingly. Perhaps you remember running a report and the next time you opened the report your previous query and parameter values were already there. This happens because of pack and unpack.
The majority of what makes pack and unpack confusing is macros, so let's do a simple example not using macros at all. Let's say we have a class that has two date values I need to persist between runs: startDate and endDate.
So when pack() gets called, I need to store both variables. (If you don't understand the way containers work, look them up on MSDN first, otherwise this won't make sense).
container pack()
{ return [startDate, endDate];
}
The framework will take whatever pack returns and store it in user data. So when the object is instantiated, unpack() gets called in order to reinitialize the values.
boolean unpack(container _packedValues)
{
[startDate, endDate] = _packedValues;
return true;
}
Follow what's happening here? We expect _packedValues to contain startDate and endDate in that order, so we assign those values to our class variables.
Now let's imagine we want to add another class variable that needs to be stored: isPosted
To do this, we'll have to modify our pack to return
[startDate, endDate, isPosted]
and our unpack to assign all three:
[startDate, endDate, isPosted] = _packedValues;
Hm, but what about values that were stored before our modification? That container assignment won't work because _packedValues will only contain 2 values (startDate and endDate). So let's make the first value in our packed data identify the version of the packed data so we can handle old values without crashing.
container pack()
{ return [1, startDate, endDate, isPosted];}
boolean unpack(container _packedValues)
{
boolean ret = true;
int version;
;
if (conpeek(_packedValues) == 1)
{
[version, startDate, endDate, isPosted] = _packedValues;
} else
{
ret = false;
}
return ret;}
Ok, so now if I need to add more variables, I need to change the version number in both pack and unpack, but now old data will make unpack() return false, which will initialize the parameter defaults.
So now let's add some macros so we only have to change one spot when we change what we want to pack. In our classDeclaration, we'll create 2 macros: one for the version of the data, and one for the values we wish to store.
classDeclaration()
{
#define.CurrentVersion(1)
#localMacro.CurrentList
startDate, endDate,
isPosted #endMacro }
If you're unfamiliar with macros, what they do is fill in exactly what the macro says at compile time. So whenever you write #CurrentVersion, the compiler fills in '1'. Whenever you write #CurrentList, the compiler fills in 'startDate, endDate, isPosted'. So now we can change our pack() and unpack() to look like this:
container pack()
{
return [#CurrentVersion, #CurrentList];
}
boolean unpack(container _packedValues)
{
int version; boolean ret = true;
;
if (conpeek(_packedValues) == #CurrentVersion)
{ [version, #CurrentList] = _packedValues;
}
else
{ ret = false; }
return ret;
}
Note:Copied from https://community.dynamics.com/ax/f/33/p/67248/122709