#644 – Chaining struct Constructors

In the same way that one constructor for a class can call another, a constructor for a struct can call another constructor, using the this keyword.  In this way, one constructor for the struct calls another, to help initialize the data in the struct.

In the example below, we define two constructors for the BoxSize struct.  The constructor that takes only two parameters chains to the three-parameter constructor, using the this keyword.

    public struct BoxSize
    {
        public double x;
        public double y;
        public double z;

        // Constructor that fully initializes the object
        public BoxSize(double x, double y, double z)
        {
            this.x = x;
            this.y = y;
            this.z = z;
        }

        // 2nd constructor that allows user to specify
        //   only X & Y and we then default Z to 1.0
        public BoxSize(double x, double y)
            : this(x, y, 1.0)
        {
        }

        public void PrintBoxSize()
        {
            Console.WriteLine(string.Format("X={0}, Y={1}, Z={2}", x, y, z));
        }
    }

#643 – The Constructor for a struct Must Initialize All Data Members

.NET requires that you initialize all memory for an object before you use it.  When it comes to a struct, this means that you must do one of three things when declaring a new instance of a struct:

  • Invoke the default parameterless constructor, which initializes all elements within the struct.  (E.g. zeroes out simple value types)
  • Declare the new instance and then set data members explicitly (assuming that they are all public)
  • Invoke a custom constructor, which initializes all data members

This means that if you define a non-default constructor for a struct, your constructor must initialize all data members in the struct before it returns. to the caller.  This guarantees that any creation of a struct-based value type will result in an object which is safe to use, because all of its data members have known values.

#642 – Reassigning the this Pointer in a struct

The this keyword in a struct refers to the current instance of the object represented by the struct.  

You can actually assign a new value to the this keyword, provided that the new value is an instance of the same struct.

    public struct BoxSize
    {
        public double x;
        public double y;
        public double z;

        public BoxSize(double x, double y, double z)
        {
            this.x = x;
            this.y = y;
            this.z = z;
        }

        public void CopyFrom(BoxSize newBoxSize)
        {
            // Overwrite existing BoxSize with a new one
            //   by assigning new value to this keyword
            this = newBoxSize;
        }

        public void PrintBoxSize()
        {
            Console.WriteLine(string.Format("X={0}, Y={1}, Z={2}", x, y, z));
        }
    }
        static void Main()
        {
            BoxSize myBox = new BoxSize(5, 2, 3);
            myBox.PrintBoxSize();

            myBox.CopyFrom(new BoxSize(10, 20, 30));
            myBox.PrintBoxSize();
        }

#641 – Using the this Keyword in a struct

In a class, the this keyword refers to the current instance of a class, or the instance that a particular method was invoked on.

You can also use the this keyword in a struct and it will refer to the current instance of the struct.

In the example below, the this keyword is used to refer to the fields of the current instance of the struct, to distinguish them from the input parameters that have the same name.

    public struct BoxSize
    {
        public double x;
        public double y;
        public double z;

        public bool HasBiggerVolume(double x, double y, double z)
        {
            if ((this.x * this.y * this.z) > (x * y * z))
                return true;
            else
                return false;
        }
    }

#638 – Defining and Using a Partial struct

In addition to classes, structs can also be partial, and contain partial methods.  Just like partial classes, a partial struct is one that is split across multiple files.  A partial method in a partial struct is a method that is declared in one portion of the struct and, optionally, implemented in another.

Like a partial method in a class, a partial method in a struct is implicitly private.

    // Dog-1.cs
    public partial struct DogDimensions
    {
        public double Height, Width, TailLength;

        partial void CustomPrintDimensions();
    }

 

    // Dog-2.cs
    public partial struct DogDimensions
    {
        partial void CustomPrintDimensions()
        {
            Console.WriteLine(
                string.Format("Dog is {0} in high, {1} in wide, and has a tail that's {2} in long",
                    Height, Width, TailLength));
        }

        public void DumpDimensions()
        {
            CustomPrintDimensions();
        }
    }

 

            DogDimensions dims;
            dims.Height = 14.0;
            dims.Width = 8.0;
            dims.TailLength = 24.0;
            dims.DumpDimensions();

#626 – Nested Type Options

When you declare one type inside of another, the outer type must be either a class or a struct.  The inner (nested) type can be one of the following: class, struct, interface, delegate or enum.

Here are a few common examples.

A struct in a class:

    public class Dog
    {
        public string Name { get; set; }

        public struct DogCollar
        {
            public int Length;
            public string Material;
        }
    }

A delegate type  defined in a class:

    public class Dog
    {
        public string Name { get; set; }

        public delegate void BarkHandler(object sender, BarkEventArgs e);
    }

An enum in a class:

    public class Dog
    {
        public string Name { get; set; }

        public enum Temperament { Docile, Excitable, Vicious };
    }

#611 – Accessibility of Members in a struct

Methods, field and properties within a struct can have one of three access modifiers, dictating the visibility of these members.

  • public – all code has access
  • private – only code within the struct has access
  • internal – code within the defining assembly has access
    public struct DogBark
    {
        public string BarkSound;
        public int BarkLength;

        // Constructor is public
        public DogBark(string barkSound, int barkLength)
        {
            BarkSound = barkSound;
            BarkLength = barkLength;
            hash = barkSound.GetHashCode();
        }

        // internal - accessible from code in the same assembly
        internal int GetHash()
        {
            return hash;
        }

        // private - accessible from code in this struct
        private int hash;
    }

#535 – Creating a Generic Struct

In addition to generic classes, you can also create a generic struct.  Like a class, the generic struct definition serves as a sort of template for a strongly-typed struct.  When you declare a variable of this struct type, you provide a type for its generic parameter.

    public struct ThreeTuple<T>
    {
        public ThreeTuple(T x, T y, T z)
        {
            X = x;
            Y = y;
            Z = z;
        }

        public T X;
        public T Y;
        public T Z;
    }

    public class Program
    {
        static void Main()
        {
            ThreeTuple<int> intTuple = new ThreeTuple<int>(32, 10, 12);
            int yVal = intTuple.Y;

            ThreeTuple<double> dblTuple = new ThreeTuple<double>(1.2, 3.4, 5.6);
            double yVal2 = dblTuple.Y;
        }
   }

#520 – Choosing Between a struct and a Class

struct and a class both encapsulate data and methods in a new type.  When you are creating a new type, you’ll generally create a new class.  But there are cases when a struct is the better choice.

Create a struct, rather than a class, when all of the following is true:

  • You want value type semantics, that is–a variable of this type directly contains the data and a copy is made whenever you assign the value to a new variable or pass the variable to a method
  • Data stored in the struct won’t be modified after an instance is created or does not change very often
  • You don’t need to inherit from another type (a struct inherits only from System.ValueType)
  • You need to store only a small amount of data in the type

#519 – Differences Between structs and classes

There are a number of differences between a struct and a class, including:

  • A struct is a value type (instance created on the stack); a class is a reference type (instance created on the heap)
  • A variable defined as a struct type contains the actual data in the struct; a variable defined as a class type references or points to the data stored in the instance of the class
  • Memory for a struct is released when its variable goes out of scope; memory for a class instance is released when the object is garbage collected
  • When a struct is assigned to a new variable, a copy is made (changes to the original are not reflected in the copy); when an instance of a class is assigned to a new variable, the new variable references the existing instance
  • When a struct is passed to a method, a copy is made