Answered by:
Global Variable in C#.NET

Question
-
I need to build a simple console app in C#.NET using VS 2013 Express. This program will start off by reading a text file which will contain a number of default configuration values which it will use when it runs. I have only a small understanding of global variables in a C# program. Most of these variables will remain the same value throughout the run, a couple of them might be changed as the code runs. But most of all I want them to be available to all classes and methods in this project. There will be about 30 or so of these global variables, possibly more. Any advice on the best way to handle this would be appreciated.
Answers
-
Greetings Bill.
In order to understand what's going on, you first need to have a grasp of how constructors usually work, and also of what the word "static" means. So here's a very simple back-to-basics tutorial. I apologise if it's telling you what you already know.
A constructor is called when an instance of a class is created. Its purpose is to perform initialisation of that instance. Here's an example.
// A class with a constructor. public class MyClass { // Some data for the class. public int Number{get; set;} // A constructor. public MyClass() { Number = 4; } } // Some code from somewhere in the rest of the program // Create an instance of MyClass. MyClass mc1 = new MyClass(); // At this point mc1.Number will be 4. // Now change it to something else. mc1.Number = 5; Create another instance of the class. MyClass mc2 = new MyClass(); // At this point mc2.Number is 4, but mc1.Number is 5.
So the constructor for MyClass is called every time we create a new instance of the class. It is not called every time we access any of the data in a class instance. When it is called, it acts on that instance alone.
If you can get a handle on that, the next thing to understand is that the word "static" essentially means "there's only one of this". That is, if it's applied to a class, there cannot be multiple instances of that class, and in fact the class cannot be instantiated at all (you can't use the "new" keyword to create it). A static class just exists as a single entity.
Now, if we put these two concepts together and come up with a "static constructor", it should be clear that we get a constructor that is used to initialise something that exists only as a single entity, so it gets executed only once. You can test this by putting a Console.WriteLine into the constructor and you will see the line being written just once.
Looking at your third question, this approach of using a static class to hold "global" data is perfectly legit. There are other ways around this problem, and object oriented fundamentalists will probably tell you that they are better ways, but if a static class works for you then go for it.
As for the second question, I can't explain that error. Unless the classes in question are in a separate file which is missing the "using System" declaration at the top.- Marked as answer by Herro wongMicrosoft contingent staff Friday, March 21, 2014 7:24 AM
All replies
-
Use a public static class and access it from anywhere. public static class MyGlobals { public const string Prefix = "ID_"; // cannot change public static int Total = 5; // can change because not const }
You can access it like
int a = MyGlobals.Total;
Ashish Pandey
- Edited by Ashish Pandey Friday, March 14, 2014 1:54 AM
- Proposed as answer by Ante Meridian Friday, March 14, 2014 2:31 AM
-
Technically there are no truly global variables in C#, in the sense that a C/C++ programmer would understand the term "global". All variables and methods must be part of a class.
The approach outlined by Ashish is what is usually used to achieve your aim. The Math class is a good standard example of this technique.
- Edited by Ante Meridian Friday, March 14, 2014 2:37 AM Just a small alteration.
-
Thanks for the replies. I like this suggested method but I don't seem to be able to adopt it to my code:
I'm getting the error message Invalid token 'foreach' in class, struct or interface member declaration. I had this kind of working but when I shifted this out of the main method I seem to be running into my lack of experience with this.using System.IO;
namespace TutorialConsoleApplication_02_ { class Program { static void Main(string[] args) { } } public static class MyGlobals { public const string vConfigFileName = "C:\\0\\ConApp.conf"; public static double vAlumCvrPltWtFt, vIe, vPlt2Frm1, vPlt2Frm2, vPlt2RibHinge, vPlt2RibNonHinge; foreach (string line in File.ReadAllLines(vConfigFileName)) { string[] vLine = line.Split('='); if (vLine[0] == "vAlumCvrPltWtFt") { vAlumCvrPltWtFt = Convert.ToDouble(vLine[1]); } if (vLine[0] == "vIe") { vIe = Convert.ToDouble(vLine[1]); } if (vLine[0] == "vPlt2Frm1") { vPlt2Frm1 = Convert.ToDouble(vLine[1]); } if (vLine[0] == "vPlt2Frm2") { vPlt2Frm2 = Convert.ToDouble(vLine[1]); } if (vLine[0] == "vPlt2RibHinge") { vPlt2RibHinge = Convert.ToDouble(vLine[1]); } if (vLine[0] == "vPlt2RibNonHinge") { vPlt2RibNonHinge = Convert.ToDouble(vLine[1]); } } } }
- Edited by Bill Tillman Friday, March 14, 2014 3:20 AM
-
Change it as
using System.IO; namespace TutorialConsoleApplication_02_ { class Program { static void Main(string[] args) { } } public static class MyGlobals { public const string vConfigFileName = "C:\\0\\ConApp.conf"; public static double vAlumCvrPltWtFt, vIe, vPlt2Frm1, vPlt2Frm2, vPlt2RibHinge, vPlt2RibNonHinge; static MyGlobals() { foreach (string line in File.ReadAllLines(vConfigFileName)) { string[] vLine = line.Split('='); if (vLine[0] == "vAlumCvrPltWtFt") { vAlumCvrPltWtFt = Convert.ToDouble(vLine[1]); } if (vLine[0] == "vIe") { vIe = Convert.ToDouble(vLine[1]); } if (vLine[0] == "vPlt2Frm1") { vPlt2Frm1 = Convert.ToDouble(vLine[1]); } if (vLine[0] == "vPlt2Frm2") { vPlt2Frm2 = Convert.ToDouble(vLine[1]); } if (vLine[0] == "vPlt2RibHinge") { vPlt2RibHinge = Convert.ToDouble(vLine[1]); } if (vLine[0] == "vPlt2RibNonHinge") { vPlt2RibNonHinge = Convert.ToDouble(vLine[1]); } } }} }
Ashish Pandey
- Edited by Ashish Pandey Friday, March 14, 2014 3:43 AM
-
Thanks very much. That got me past the error messages. And please forgive my newbie status here but I need a little more advice on how to call this into action. So let me explain what I understand about it and perhaps you can tell me where I'm going wrong:
The line you added was
static MyGlobals()
As I understand it this is a new method called MyGlobals added to the existing MyGlobals class and you placed it around the code where I call the conf file and read the lines from it.
So my thinking is that in the Main method, I could do this:
MyGlobals();
or
MyGlobals;
and the code would run through the MyGlobals class which would assign values to the global variables. But this of course does not work. Again, this is all new territory for me so I could use a little more help on how to now use that new class so that once those variables are assigned, any class or method inside of this project can use them.
-
Thanks very much. That got me past the error messages. And please forgive my newbie status here but I need a little more advice on how to call this into action. So let me explain what I understand about it and perhaps you can tell me where I'm going wrong:
The line you added was
static MyGlobals()
As I understand it this is a new method called MyGlobals added to the existing MyGlobals class and you placed it around the code where I call the conf file and read the lines from it.
So my thinking is that in the Main method, I could do this:
static void Main(string[] args) { Console.WriteLine(MyGlobals.vAlumCvrPltWtFt); Console.ReadKey(); }
But this would mean that each time I call on one of these variables, it would have to go out and read that file over and over again. I want to use this external file because it will make it much easier to change certain variables in this project without having to recompile the code each time.
-
Hi
static MyGlobals(){} is a static constructor it is called automatically when you access any member of MyGlobals class first time in Application.
You can access variables of MyGlobals as
double a = MyGlobals.vAlumCvrPltWtFt;
http://msdn.microsoft.com/en-us/library/k9x6w0hc.aspx
Ashish Pandey
- Edited by Ashish Pandey Friday, March 14, 2014 3:20 PM
-
I "C" my friend .... pun intended. But wouldn't that still mean that each time I call the MyGlobal class it will go read that text file again and again. Not that this short project would notice any time delay, but wouldn't there be a more efficient way of coding this...or am I misunderstanding your reply in which you say it would only be accessed the first time I call it. So any subsequent calls to it would not mean another disk read?
-
-
Okay, I checked out the link Ashish referenced and accordingly read this:
A static constructor is used to initialize any static data, or to perform a particular action that needs to be performed once only. It is called automatically before the first instance is created or any static members are referenced.
I think I understand that but can someone be so kind as to put it in laymen's terms. The code I worked on now looks like this:
using System.IO; using System; namespace TutorialConsoleApplication_02_ { class Program { static void Main(string[] args) { Console.WriteLine( "(1). Weight/SqFt for Alum: . . . . . . . . . . . . . {0:G}\n" + "(2). Inertia for Alum: . . . . . . . . . . . . . . {1:0,0}\n" + "(3). Some critical dim: . . . . . . . . . . . . . . {2:G}\n" + "(4). Some critical dim: . . . . . . . . . . . . . . {3:G}\n" + "(5). Some critical dim: . . . . . . . . . . . . . . {4:G}\n" + "(6). Some critical dim: . . . . . . . . . . . . . . {5:G}\n", MyGlobals.vAlumCvrPltWtFt, MyGlobals.vIe, MyGlobals.vPlt2Frm1, MyGlobals.vPlt2Frm2, MyGlobals.vPlt2RibHinge, MyGlobals.vPlt2RibNonHinge); Console.ReadKey(); } public static class MyGlobals { public static double vAlumCvrPltWtFt, vIe, vPlt2Frm1, vPlt2Frm2, vPlt2RibHinge, vPlt2RibNonHinge; static MyGlobals() { // READ THE CONFIGURATION TEXT FILE foreach (string line in File.ReadAllLines("C:/0/ConApp.conf")) { string[] vLine = line.Split('='); if (vLine[0] == "vAlumCvrPltWtFt") { vAlumCvrPltWtFt = Convert.ToDouble(vLine[1]); } if (vLine[0] == "vIe") { vIe = Convert.ToDouble(vLine[1]); } if (vLine[0] == "vPlt2Frm1") { vPlt2Frm1 = Convert.ToDouble(vLine[1]); } if (vLine[0] == "vPlt2Frm2") { vPlt2Frm2 = Convert.ToDouble(vLine[1]); } if (vLine[0] == "vPlt2RibHinge") { vPlt2RibHinge = Convert.ToDouble(vLine[1]); } if (vLine[0] == "vPlt2RibNonHinge") { vPlt2RibNonHinge = Convert.ToDouble(vLine[1]); } } // END FOREACH } // END MyGlobals() METHOD } // END MyGlobals() CLASS public static class testing123 { double v = MyGlobals.vPlt2Frm1; } } // END CLASS
public static class testing321 { double v1 = Program.MyGlobals.vPlt2Frm1; } } // END NAMESPACE
And it works but I am still unsure about certain things.
- Does the class MyGlobals get executed only once as the note on the static constructor indicates or does it get called each and every time I try to use one of the MyGlobal variables? And in being called is it going to do a disk read each time?
- I added a couple of new classes to this outside of the Program Class to test that I can call these MyGlobal variables from other classes, methods, etc... But when I try to use a simple Console.WriteLine command, I'm being told that there is no WriteLine
method available.
- I am still new to all this and I need to get a better understanding of how to use variables that will maintain their value throughout the entire project. I understand that using Global variables is not standard programming practice these days, but I need some place to hold values which will be used throughout the project. And my goal is to place these in a config file (text file) or in a MySQL database so that when and if the people in charge want to change them we will not be forced to recompile the C# projects but simply make changes to the values in the database or config file. Hope this makes sense.
- Edited by Bill Tillman Monday, March 17, 2014 1:13 PM
- Does the class MyGlobals get executed only once as the note on the static constructor indicates or does it get called each and every time I try to use one of the MyGlobal variables? And in being called is it going to do a disk read each time?
-
And it works but I am still unsure about certain things.
- Does the class MyGlobals get executed only once as the note on the static constructor indicates or does it get called each and every time I try to use one of the MyGlobal variables? And in being called is it going to do a disk read each time?
- I added a couple of new classes to this outside of the Program Class to test that I can call these MyGlobal variables from other classes, methods, etc... But when I try to use a simple Console.WriteLine command, I'm being told that there is no WriteLine
method available.
- I am still new to all this and I need to get a better understanding of how to use variables that will maintain their value throughout the entire project. I understand that using Global variables is not standard programming practice these days, but I need some place to hold values which will be used throughout the project. And my goal is to place these in a config file (text file) or in a MySQL database so that when and if the people in charge want to change them we will not be forced to recompile the C# projects but simply make changes to the values in the database or config file. Hope this makes sense.
1. Yes, the constructor for the static class MyGlobals will get called only once -- when the value is first accessed. Sometimes, seeing is believing. Unfortunately, I don't believe you can put a break point in static constructor; but, you can insert WriteLine() at different points in the code to see the sequence of events. Give the following code sample a try. See when the constructor is called.
class Program { public static class MyGlobals { public static int Value1; public static int Value2; static MyGlobals() { Console.WriteLine("static constructor"); Value1 = 1; Value2 = 2; } } static void Main(string[] args) { Console.WriteLine("Main()"); Debugger.Break(); int v1 = MyGlobals.Value1; // this one will trigger the constructor Console.WriteLine("Value1 = " + v1.ToString()); Debugger.Break(); int v2 = MyGlobals.Value2; // this one won't Console.WriteLine("Value2 = " + v2.ToString()); Debugger.Break(); Console.WriteLine("Done"); } }
2. Based on the last section of your code block, you need to call Console.WriteLine() inside a function. Modify the class testing321 to this.
public static class testing321 { public static void Test() { double v1 = Program.MyGlobals.vPlt2Frm1;; Console.WriteLine("testing321"); } }
3. I think this is more of a design decision. For me, if the values do not change (for example, default configurations), it is perfectly fine keeping values in global variables. The problem comes when function started to change the values of the global variables. In which case, I would steer away from it because this will turn into a debugging nightmare fast for it's difficult to track down where the values get changed.
- Edited by schen0614 Tuesday, March 18, 2014 12:19 AM
- Does the class MyGlobals get executed only once as the note on the static constructor indicates or does it get called each and every time I try to use one of the MyGlobal variables? And in being called is it going to do a disk read each time?
-
Greetings Bill.
In order to understand what's going on, you first need to have a grasp of how constructors usually work, and also of what the word "static" means. So here's a very simple back-to-basics tutorial. I apologise if it's telling you what you already know.
A constructor is called when an instance of a class is created. Its purpose is to perform initialisation of that instance. Here's an example.
// A class with a constructor. public class MyClass { // Some data for the class. public int Number{get; set;} // A constructor. public MyClass() { Number = 4; } } // Some code from somewhere in the rest of the program // Create an instance of MyClass. MyClass mc1 = new MyClass(); // At this point mc1.Number will be 4. // Now change it to something else. mc1.Number = 5; Create another instance of the class. MyClass mc2 = new MyClass(); // At this point mc2.Number is 4, but mc1.Number is 5.
So the constructor for MyClass is called every time we create a new instance of the class. It is not called every time we access any of the data in a class instance. When it is called, it acts on that instance alone.
If you can get a handle on that, the next thing to understand is that the word "static" essentially means "there's only one of this". That is, if it's applied to a class, there cannot be multiple instances of that class, and in fact the class cannot be instantiated at all (you can't use the "new" keyword to create it). A static class just exists as a single entity.
Now, if we put these two concepts together and come up with a "static constructor", it should be clear that we get a constructor that is used to initialise something that exists only as a single entity, so it gets executed only once. You can test this by putting a Console.WriteLine into the constructor and you will see the line being written just once.
Looking at your third question, this approach of using a static class to hold "global" data is perfectly legit. There are other ways around this problem, and object oriented fundamentalists will probably tell you that they are better ways, but if a static class works for you then go for it.
As for the second question, I can't explain that error. Unless the classes in question are in a separate file which is missing the "using System" declaration at the top.- Marked as answer by Herro wongMicrosoft contingent staff Friday, March 21, 2014 7:24 AM
-
Thanks. This is all very helpful information and obviously I have some more studying to do. However, I think I can see that at least I'm on one of the right tracks.
The goal is to have the variables which will not change, unless a major design change is made, or they change the weight per sq foot of 1/4" aluminum diamond plate, etc... and those will happen only once in a blue moon, in an external location like a MySQL database or a simple text file. Something that even the most novice user could be instructed on how to edit them in the event one of the major changes takes place. This way, no one has to go back into the code and recompile and redistribute new copies of the exe's. And outside of a rare exception here or there, I think it's safe to assume that once the variables are assigned, no changes to them will take place or be needed. In fact, this is a structural calculation project which runs all it's math in less than a few seconds and then exits. So global variables like this are a good application.
- Edited by Bill Tillman Tuesday, March 18, 2014 12:43 PM