Professor Mustard Programming
 

Programming 101 - Unit 03 - Modularity

03d) Member Variables
 
With the addition of the "ref" and "out" keywords, we now have many different ways to pass variables between methods. However, there's one last trick to learn, and that is variables which are completely independent of methods. Look at this:

class Class1
{
  static int _count;

  [STAThread]
  static void Main(string[] args)
  {
    _count = 5;
  }
}



The variable "_count" has been declared outside of the Main() method. In fact, it's not in a method at all; it's just sitting out there in "Class1", at the same "level" of scope as all your methods. The obvious advantage to this is that any and every method has access to _count, without having to pass stuff around. _count will exist as long as your program in Class1 exists.

If you're wondering about the underscore in front of its name, it's just a prefix that many programmers put in front of these "member" variables. It reminds us that the variable exists throughout all of Class1. In addition to this, remember that you can't have duplicate variable names in the same scope. So, if we called it plain old "count", it might be a pain, because we wouldn't be able to use that name in any other method within Class1. But hey, at the end of the day, it's just a naming standard; take it or leave it. Personally, I use it all the time.

And if you're wondering why we used the word "static" in front of our variable (which we've never, ever done with variables before), don't worry about it yet: a full explanation of "static" and what it means will be provided once we get into Object Oriented Programming (OOP). For now, just make sure that anything you declare in "member" scope (that is, within "Class1" but not in a method),  needs the word "static" in its definition.

That being said, I should probably mention the biggest problem with member variables: any and every method in Class1 has access to them. Yeah, I know, I just finished saying that it was an advantage. But, say that Class1 is 10,000 lines long, and full of methods that perform operations on a member variable. When you finally run the program, what if you find that the variable's value didn't come out the way you expected? That means there's a bug in your code... where do you want to start looking? Because it's a member variable, any method in Class1 could have screwed it up at. And indeed, because our entire program exists within Class1, that screw-up could have occurred at any point in your program's execution. It could be a bad formula, a missed step, or even a line that sets it to a hard-coded value. You just don't know.

That's the nice thing about the parameter/return value approach to sharing information in your program: it's self-contained. What happens in method A doesn't generally affect method B. But as soon as method A and B start sharing the same member variable, you lose that isolation of responsibility, and your entire program becomes much more difficult to trace. However, this isn't to say that you don't want to share variables within a class. As you get into OOP, you will find that having a certain number of member variables in a class is inevitable (and in most cases, desirable). But when our entire program exists in once class, as it does now, declaring a variable in "member" scope has almost the same effect as the dreaded "global" variables you could create in Visual Basic and C++. Those languages actually let you declare variables outside of the class itself, and I just find that spooky!

What if you want your program to include information that is accessible at the "member" level, but you don't want it to be changed? Well, you can apply the keyword "readonly" to any variable in member scope...

static readonly string _version = "1.0";


Once the program's up and running, the program will not permit any changes to _version. The program only assigns to it once, using the value that you've provided. This is handy for defining information that doesn't change during the course of a program's execution (version numbers, or the number of days in a week, for example). There's also a keyword called "const", which does something similar, but we'll have to get into classes before you can fully appreciate the difference. Just use readonly for now.

To demonstrate the joys and hazards of member variables, the following code sample shows how you can use one anywhere.



using System;

namespace D_Member
{
  class Class1
  {
    static readonly string _version = "1.0";
    static int _count;

    [STAThread]
    static void Main(string[] args)
    {
      PrintVersion();

      PrintCount();
      IncreaseCount(50);
      DecreaseCount(10);
      PrintCount();
      IncreaseCount(20);
      DecreaseCount(50);
      PrintCount();

      _count = 0; // Render everything we did meaningless
      PrintCount();

      PromptForExit();
    }

    static void IncreaseCount(int amount)
    {
      _count += amount;
      Console.WriteLine( "Increased count by " + _count );
    }

    static void DecreaseCount(int amount)
    {
      _count -= amount;
      Console.WriteLine( "Decreased count by " + _count );
    }

    static void PrintCount()
    {
      Console.WriteLine( "Count's current value is " + _count );
    }

    static void PrintVersion()
    {
      Console.WriteLine( "Version " + _version );
    }

    static void PromptForExit()
    {
      Console.Write(Environment.NewLine + "Program complete! Hit enter to exit...");
      Console.ReadLine();
    }
  }
}