#197 – Checking an Enumerated Value for the Presence of a Flag

You can combine enum type flags using the bitwise OR operator.  You can also use the bitwise AND operator to check an enumerated value for the presence of a flag.

            Talents fredTalents = Talents.Singing | Talents.Dancing;
            Talents ernieTalents = Talents.Singing | Talents.Juggling | Talents.JokeTelling;

            bool fredCanDance = (fredTalents & Talents.Dancing) == Talents.Dancing;
            bool ernieCanDance = (ernieTalents & Talents.Dancing) == Talents.Dancing;

When a Talents value is bitwise AND’d (&) with a specific flag, e.g. Talents.Dancing, every bit except for the Dancing bit is clear in the value.  The resulting value, of type Talents, is therefore either equal to 0 or to Talents.Dancing.

We could also write the last two lines as:

            bool fredCanDance = (fredTalents & Talents.Dancing) != 0;
            bool ernieCanDance = (ernieTalents & Talents.Dancing) != 0;
Advertisement

#196 – Using the ToString() Method on a Flags-Based Enum Type

When you use the ToString method on an enumeration type that has been defined with the Flags attribute, the method correctly decomposes the current value into its constituent flags.

Assuming the following enumeration type:

        [Flags]
        public enum Talents {
            Singing = 1,
            Dancing = 2,
            Juggling = 4,
            JokeTelling = 8};

And the following enumerated values:

            Talents wcFields = Talents.Juggling;
            Talents fredTalents = Talents.Singing | Talents.Dancing;
            Talents ernieTalents = Talents.Singing | Talents.Juggling | Talents.JokeTelling;

The ToString method, implicitly called by Console.WriteLine, produces the following output:

            Console.WriteLine(wcFields);            // Juggling
            Console.WriteLine(fredTalents);         // Singing, Dancing
            Console.WriteLine(ernieTalents);        // Singing, Juggling, JokeTelling

#195 – Using an Enum Type to Store a Set of Flags

If you represent a set of boolean values as bits in a larger word, you’ll notice that each flag can be represented by a value that is a power of two.

  • Singing = Bit 0 = 0 0 0 1 = 1
  • Dancing = Bit 1 = 0 0 1 0 = 2
  • Juggling = Bit 2 = 0 1 0 0 = 4
  • Joke-Telling = Bit 3 = 1 0 0 0 = 8

You can use an enum type to represent these flags.

        [Flags]
        public enum Talents {
            Singing = 1,
            Dancing = 2,
            Juggling = 4,
            JokeTelling = 8};

We can use a variable of type Talents to represent either a single talent:

            Talents sinatra = Talents.Singing;    // 1
            Talents wcFields = Talents.Juggling;  // 4

Or we can represent a set of talents using a bitwise OR operator:

            Talents fredTalents = Talents.Singing | Talents.Dancing;    // 1 + 2 = 3
            Talents ernieTalents = Talents.Singing | Talents.Juggling | Talents.JokeTelling;    // 1 + 4 + 8 = 13

The Flags attribute indicates that this enum type can be used to store a set of flags.  Using a different bit for each flag means that we can store any combination of flags at the same time.

#194 – Storing a Set of Boolean Values as Bits

You might want to store a set of boolean values in a single variable.  For example, you could keep track of a person’s talents, recording which talents each person has.

E.g.:

  • Fred: good at Singing, Dancing
  • Sally:  good at Dancing, Juggling
  • Ernie: good at Juggling, Joke-Telling, Singing

One way to store this information is to represent each talent with a single bit in a larger word and to then use the entire word to represent a person’s talents.  A bit value of 1 indicates that the person has the talent and 0 indicates that they do not have the talent.  Each person can have 0 or more talents.

For example, we could store information about four talents using four bits:

  • Bit 0 (rightmost) – Singing
  • Bit 1 – Dancing
  • Bit 2 – Juggling
  • Bit 3 (leftmost) = Joke-Telling

Here are the bit patterns for the sets of talents listed above (each word is 4 bits):

  • 0 0 1 1 = Dancing + Singing  (Fred)
  • 0 1 1 0 = Juggling + Dancing  (Sally)
  • 1 1 0 1 = Joke-Telling + Juggling + Singing  (Ernie)

#193 – An Enum Type’s ToString Method Displays the Member’s Name

Normally, when you call the ToString method on a variable that stores an integer value, the value of the integer is displayed.

            int x = 42;
            Console.WriteLine(x.ToString());   // Displays: 42
            Console.WriteLine(x);     // Same thing--ToString implicitly called

If you call ToString on an enum type variable, however, the textual name of the enumerated member is displayed.

        public enum Mood {
            Crabby = -5,
            Happy = 5,
            Petulant = -2,
            Elated = 10};

        static void Main()
        {
            Mood myMood = Mood.Crabby;
            Mood dogsMood = Mood.Elated;

            Console.WriteLine(myMood);     // ToString implicitly called; displays: Crabby

            Console.WriteLine(dogsMood);   // Displays: Elated
        }

#192 – Using Non-Default Constant Values for Enumeration Members

When you define an enum type, the members contained in your enumeration take on constants starting at zero (for the first member) and then incrementing by one (for consecutive members).

        public enum Mood {
            Crabby,       // 0
            Happy,        // 1
            Petulant,     // 2
            Elated };     // 3

You can, however, specify the constant value to use for each member.  You can specify constants in any order.  Members that don’t have a value specified take on a value one greater than the previous member.

        public enum Mood { 
            Crabby = -5,       
            Happy = 5,        
            Petulant = -2,     
            Elated = 10};

        public enum Weekday
        {
            Sunday = 1,
            Monday,     // 2
            Tuesday,    // 3, etc.
            Wednesday,
            Thursday,
            Friday,
            Saturday
        };

#191 – Changing the Underlying Type of an enum

When you declare an enum, by default each enumerated value is represented internally with an int.  (System.Int32 – 4 bytes).  But you can use any of the following types: byte, sbyte, short, ushort, uint, long, or ulong.

        public enum Mood { Crabby, Happy, Petulant, Elated };   // type is int

        public enum MoodByte : byte { Crabby, Happy, Petulant, Elated };

        static void Main()
        {
            // 4 bytes
            Console.WriteLine("Each element is {0} bytes", sizeof(Mood));

            // 1 byte
            Console.WriteLine("Each element is {0} bytes", sizeof(MoodByte));
        }

#190 – Memory Management for Heap-Based Objects

In C#, you create an object on the heap when you instantiate an object using the new keyword.

            Person general = new Person("Julius", "Caesar");

We now have a Person object on the heap and a reference to that object–the variable general.

We can also declare a second variable that references the same object.

            Person antonysFriend = general;

Now we have one Person object on the heap and two references to it.

The memory for an object on the heap can be freed when it’s no longer being referenced by any variables.  This can happen when the variables that reference it go out of scope, or when they are set to point to another object.

More precisely, the memory will be reclaimed by the Garbage Collector (GC) in .NET.  When an application needs more memory, the GC is triggered and it releases memory for any dead objects.

#189 – Memory Management for Stack-Based Objects

When an object is created on the stack, memory is allocated from the stack for that object.

Memory for an object allocated from the stack is not deallocated until the function containing the declaration exits.

        static void Main(string[] args)
        {
            int x = 42;

            SomeMethod();

            // x deallocated when Main() exits
        }

        static void SomeMethod()
        {
            int y = 100;
            int z = 12;
            int sum = y + z;

            // y, z, sum all deallocated when SomeMethod() exits
        }

In practice, you don’t care much when memory for an object is deallocated.  Instead, you care more about the block of code within which you can refer to and use the variable–its scope.

#188 – Objects Are on the Heap, References to Objects Are on the Stack

When you instantiate an object, an area of memory on the heap is allocated to store the object’s data.  So we typically say that the object is on the heap.

            Person thatGuy = new Person("Julius", "Caesar");

In the above example, a new instance of the Person class is created and the data for this Person is stored on the heap.

But in creating a new instance of a Person, we also had to declare and instantiate a reference to the Person object that we just created.  That reference is stored on the stack.

In the same way that value types are normally stored on the stack, but can be on the heap if they exist within another object, object references can also be on the heap if they are contained within other objects.