From an email we received the other day:
I am converting an old AVR Classic Windows app to an AVR for .NET Windows app. The app has several special-case areas and third-party controls that make it a candidate for this manual rewrite instead of trying to automate the process with the ASNA Upgrade Assistant.
The AVR Classic app has, as we did as a general best practice back in the old days, a zillion global variables. As I rewrite the AVR for .NET app, I am doing my best to minimize the number of global variables required, but I am finding that no matter what, I am still going to need several in the new version of the program. In AVR Classic, anything we put in the startup form (or VRP) was global to the project; I can’t find anything that provides this global-to-the-project functionality in AVR for .NET. Am I missing something?
Thank you very much,
Hunting for global variables
Dear “Hunting for global variables,”
You are missing something, but it’s subtle so don’t think less of yourself for missing it!
Before we get to the solution, let’s make something very clear: the technique shown here should never be used by ASP.NET browser-based apps. We’ll get to the reason for that at the end of this article. But first, here is a good solution for global variables for your Windows programs.
Global project variables in AVR for .NET Windows apps
Create a class in your project and call it
Globals. Do this by right-clicking on the project in the Visual Studio Solution Explorer and selecting the “Add…” context menu option and then selecting the “Class…” option. You’ll be prompted for a file name; name it
Globals.vr. Be sure to make this class
Declare as many variables as you need in this class, of any type. Be sure to mark these variables as
Shared(Yes). Both keywords are very important. An example class is shown below. Although only one field is shown here, you can add as many other fields, of any type, as needed.
BegClass Globals Access(*Public)
DclFld Rate Type(*Integer4) Access(*Public) Shared(*Yes)
... as many other Public/Shared values declared here as necessary.
In the AVR Classic days, it was a common practice use Hungarian notion to give global variables a special prefix to make it easy to identify the global variables in your source. For example,
gRate might have been used for the name of the
Rate global variable above. Don’t do this in .NET–just give the variable a good, meaningful, field name. You quickly see that
Shared(*Yes) variables come with a free prefix!
Shared variables are known in VB.NET and C# as static variables. AVR gets a little murky here because in addition to its
Shared() keyword, AVR also provides a
Static() keyword see this article in this issue of this newsletter for an explanation of the
An AVR shared variable is owned by the class not an instance of the class. Therefore, you don’t need to instance the
Globals class to use its shared variables. To use the Rate global variable from anywhere in your project, just type
Global.Rate. This makes the variable available, with read/write access, anywhere in your Windows application. The
Global class name fills in for the missing Hungarian notation. You also get a little help from Intellisense with these variables. After you type
Global and the period Intellisense shows you a list of your global variables.
The example class above doesn’t use a
Namespace directive. But if it did and the
Globals class isn’t within the same namespace as your app, you may need either a
Using statement or to fully qualify the
Globals class. For example, if the
Globals class is namespaced as
Utilities you either need a
Using Utilities statement at the top of any class needing the global variables or to reference the variables as
Utilities.Globals.Rate (where Rate may be any shared variable in the class.)
Variables from this
Globals class are available from any class in your AVR for .NET Windows project. There isn’t anything magic about the
Globals class; any variable declared
Shared(Yes) in any class would be available anywhere in your Windows apps. However, rather than frittering these variables across many classes, it’s probably better to keep them all in one class.
Variables declared with
Shared(Yes) can be any type, including database connections (
DclDB) and disk files (
DclDiskFile). Be very careful using the technique for any variables that aren’t scalar values, though. The notion of being able to move the record position of a file from any Windows form could introduce some pesky bugs.
You’ll notice that the
DclConst operation doesn’t have a
Shared() keyword. Public constants are always implicitly shared.
One more caution: The road to programming hell is paved with global variables (as discussed in Steve McConnells’ superb book, Code Complete 2nd Edition). The whole point of .NET’s object-oriented programming model is to provide effective application partitioning. The loose coupling provided by declaring variables local to subroutines and functions makes your code easier to debug and maintain. With each global variable you introduce you add exponentially appearing opportunities for hard-to-find bugs. Avoid global variables whenever you can!
Don’t use do this in ASP.NET applications!
Be very aware that public/shared variables have a sinister side-effect in ASP.NET browser-based apps: these variables are shared by all users of the Web app! Limit your use of public/shared variables in ASP.NET apps to pure functions and constants. Anything else and you’re asking for big trouble! For ASP.NET apps, use session storage to provide global variables for your app.