Following this reply (intersing subject, IMO).
I used a KeyedCollection<> because I wanted the items to be ordered (in the order they were added), so I could restore their values in the reverse order.
Interesting subject, indeed; although the general use case is somehow shrouded in mystery. You are mutating the state of the application, then you want - come what may - its original state restored. You're doing this in a way that necessitates the management of an IDisposable collection. How complex is your control flow that you can't just be using the using (C#) statement?
Before we start counting trees, let me show you the whole forest.
Your question has an easy answer. In most high-level customization and scripting, we can identify a 'standard' or common set of system variables that are always saved, changed, and restored by numerous custom commands (namely those that use acedCmd() to script AutoCAD commands), so the underlying logic behind the design of LocalSystemVariables which I did not endeavour to illustrate up to this point, is that it can be specialized, and a specialization of it can handle that set of commonly-managed system variables internaly, rather than having to specify that same set of system variables explicitly in each and every custom command implementation that used the base type.
public class CommandScriptingEditorState : LocalSystemVariables
{
public CommandScriptingEditorState()
{
// This is just an example of some of the 'common'
// sysvars that are always saved/changed/restored
// when AutoCAD commands are scripted via acedCmd().
base["CMDECHO"] = 0;
base["BLIPMODE"] = 0;
base["HIGHLIGHT"] = 0;
base["OSMODE"] = 0;
}
}
With the above, whenever I need to write a command that itself scripts other AutoCAD commands (via acedCmd), instead of using a LocalSystemVariables instance, I would use a specialization of it, like the one shown above, that will internally manage the system variables that are always managed when scripting AutoCAD commands, and with that, my top-level application logic is
vastly simplified, to a far greater extent than what you've presented.
[CommandMethod("MYCOMMAND")]
public static void MyCommand()
{
using( new CommandScriptingEditorState
() ) {
// script AutoCAD commands via acedCmd() here,
// all of the system variables that are managed
// internally by CommandScriptingEditorState()
// are saved/changed/restored for us.
}
}
Here's another example of a more-complicated specialization of the above specialization that serves to simplify a few common tasks in consuming code, namely changing current editor entity properties to values that will be inherited by new objects created via command scripting:
// Simplifies code logic of applications that script AutoCAD
// commands and often need to control common properties
// of entitites created by scripted AutoCAD commands:
public class CurrentEditorProperties : CommandScriptingEditorState
{
public CurrentEditorProperties( string layer = null, string color = null, string linetype = null )
: base()
{
// The defaults are the current values:
base["CLAYER"] = layer ?? base["CLAYER"];
base["CECOLOR"] = color ?? base["CECOLOR"];
base["CELTYPE"] = linetype ?? base["CELTYPE"];
}
public string Layer
{
get
{
return base["CLAYER"];
}
set
{
base["CLAYER"] = value;
}
}
public string Color
{
get
{
return base["CECOLOR"];
}
set
{
base["CECOLOR"] = value;
}
}
public string Linetype
{
get
{
return base["CELTYPE"];
}
set
{
base["CELTYPE"] = value;
}
}
}
// Example:
[CommandMethod("MYCOMMAND")]
public static void MyCommand()
{
using( var props
= new CurrentEditorProperties
( "WALLS",
"BYLAYER",
"BYLAYER" ) ) {
// script AutoCAD commands via acedCmd() here.
// In addition to the common system variables
// managed by its base class, the current layer,
// color, and linetype sysvars are managed by
// the CurrentEditorProperties instance.
//
// If you need to change the property assigned
// to objects subsequently created by scripted
// commands, it's just this easy:
props.Layer = "DOORS";
// Insert some doors...
// and then change it again:
props.Layer = "WINDOWS";
// Insert some windows....
// and when you're done, the original current
// layer, color, and linetype, along with all
// the system variables managed by the base type
// are restored to what they were before your
// command was started.
}
}
Now, Is that
application-level code logic simple enough?
[edit TT]: renamed CommandScriptSystemVariables to CommandScriptingEditorState
kdub:edit code=csharp