Chapter 1: Lesson 1: Using Value Types

johnmora's picture

Value types are variables which contain their data directly as opposed to reference types  which store only a reference to the data stored elsewhere. Instances of value types are stored in an area of the memory called the “stack” where the runtime can manipulate them quickly with minimal overhead.

Three general value types are: Built in types, User defined types and Enumerations. Each of these types are derived from the .NET Framework System.ValueType base type. All built in numeric types are value types and you choose a numeric type based on the size of the values you expect to work with. Some common built in numeric value types are:

(This is NOT a complete list)

Type
(.NET alias)
Bytes Range Use for
System.SByte
(SByte/sbyte)
1 -128 to 127 Signed byte values
System.Int16
(Short/short)
2 -32768 to 32767 Interoperation and other uses
System.Single
(Single/float)
4 -3.402823E+38 to 3.402823+E38 Floating point numbers
System.Decimal
(Decimal/decimal)
16 -79228162514264337593543950335 to 79228162514264337593543950335 Financial and Scientific calculations requiring  great precision

Numeric types are used so frequently that .NET has defined aliases for them. Using the alias is equivalent to using the full type name. In addition to numeric types, the non-numeric value types listed below are also value types:

(This is NOT a complete list)

Type
(.NET alias)
Bytes Range Use for
System.Char
(Char/char)
2 NA Single Unicode characters
System.Boolean
(Boolean/bool)
1 NA True/False values

There are about 300 more value types in the .NET Framework. When you assign between value-type variables, the data is copied from from one variable to the other and is stored in two different locations on the stack. This is different than reference types which will be explained later.

Even though value types usually reference simple values, they still function as objects and you can call methods on them. As an example you can call the ToString() method when displaying values as text. ToString() is overridden from the base System.Object type.

Declaring the Value Type Variable

   1: //I will be using C# for all my examples
   2: bool b = false
   3: //You declare a variable as nullable if you want to be able to determine wether a value has been assigned
   4: Nullable<bool> b = null;
   5: //Shorthand method for C# only
   6: bool? b = null;

Declaring a value as nullable enables the HasValue and the Value members, as shown below:

   1: //Use HasValue to detect whether a value has been set
   2: if(b.HasValue){
   3:     Console.WriteLine("b is {0}.", b.Value);
   4: } else {
   5: Console.WriteLine("b is not set.");
   6: }

How to Create User-Defined Types (Structures)

User defined types are also called structures or simply “structs” and just like any other value type they are stored on the stack and contain their data directly. Structs also behave nearly identical to classes. Structures are a composite of other types which make it easier to work with those types. You define structures by using the Structure keyword (C#).

Example of a User-Defined Type or Structure (could also be declared as a class):

   1: struct Cycle{
   2:     //Private fields
   3:     int _val, _min, _max;
   4:     //Constructor
   5:     public Cycle(int min, int max){
   6:         _val = min;
   7:         _min = min;
   8:         _max = max;
   9:     }
  10:     public int Value{
  11:         get { return _val; }
  12:         set {
  13:             if (value > _max){
  14:                 this.Value = value - _max + _min - 1;
  15:             } else {
  16:                 if (value < _min){
  17:                     this.Value = _min - value + _max - 1;
  18:                 } else {
  19:                     _val = value;
  20:                 }
  21:             }
  22:         }
  23:     }
  24:     public override string ToString(){
  25:         return Value.ToString();
  26:     }
  27:     public int ToInteger(){
  28:         return Value;
  29:     }
  30:     public static Cycle operator +(Cycle arg1, int arg2){
  31:         arg1.Value += arg2;
  32:         return arg1;
  33:     }
  34:     public static Cycle operator -(Cycle arg1, int arg2){
  35:         arg1.Value -= arg2;
  36:         return arg1;
  37:     }
  38: }

This “Cycle” structure could easily be converted form a Value type to a Reference type by changing the Structure/struct keyword to Class. If you do make that change, instances of Cycle will be allocated on the managed heap rather than as 12 bytes on the stack (4 bytes for each private integer field). While the functionality is similar, structures are normally more efficient than classes. You should define a structure over a class if the type will perform better as a value type than a reference type.

*Structures should meet these criteria:

  • Represents a singe value logically.
  • Has an instance size less than 16 bytes.
  • Is not frequently changed after creation.
  • Is not a cast to a reference type. (Casting is the process of converting between types.)

How to create Enumerations

Enumerations are related symbols that have fixed values. Use enumerations to provide a list of choices for developers using your class.

Example of an enumeration:

   1: enum Titles { Mr, Ms, Mrs, Dr, Geek };
   2: //Create instance of Titles type
   3: Titles t = Titles.Dr
   4: //Displays "Dr."
   5: Console.WriteLine("{0}.", t);

The purpose of enumerations is to simplify coding, avoid programming errors and improve code readability by using meaningful symbols instead of simple numeric values. Use enum’s when you want to have developers consuming your types to choose from a limited set of choices for each value.

Putting what we have learned together

   1: class Person{
   2:     //Public members
   3:     public string firstName;
   4:     public string lastName;
   5:     public int age;    
   6:     public Genders gender;    
   7:     //Declare new Enumeration with two possible values "Male, Female"
   8:     public enum Genders { Male, Female };
   9:     public Person(string _firstName, string _lastName, int _age, Genders _gender){
  10:         firstName = _firstName;
  11:         lastName = _lastName;
  12:         age = _age;
  13:         gender = _gender;
  14:     }
  15:     //Override ToString() method to display all members
  16:     public override string ToString(){
  17:         return firstName + " " + lastName + " (" + gender + "), age " + age;
  18:     }
  19: }

Example of consumption of above class:

   1: //in the Main method of your program Construct an instance of the Person structure
   2: Person p = new Person("Teh", "QuadFather", 32, Person.Genders.Male);
   3: Console.WriteLine(p.ToString());

Trackback URL for this post:

http://blog.codetales.com/trackback/15

Powered by Drupal - Design by artinet