#627 – Accessibility of Nested Types in a struct or a class

When you define a type within the scope of a class (a nested type), the accessibility of the nested type can be one of the following

  • public
  • protected internal
  • protected
  • internal
  • private  (default)

When you define a type within a struct, the choices for accessibility of the nested type are more limited and include:

  • public
  • internal
  • private  (default)

Remember that the outer type (the class or struct) has more limited accessibility choices:

  • public
  • internal  (default)
Advertisement

#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 };
    }

#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

#259 – Static vs. Instance Properties

A typical property declared in a class is an instance property, meaning that you have a copy of that property’s value for each instance of the class.

You can also define static properties, which are properties that have a single value for the entire class, regardless of the number of instances of the class that exist.

    public class Dog
    {
        // An instance property--one copy for each dog
        public string Name { get; set; }

        // A static property--one copy for all dogs
        public static string Creed { get; set; }
    }

You can read and write a static property even if no instances of the class exist.  You use the class’ name to reference a static property.

            // Writing an instance property  (Name)
            Dog kirby = new Dog();
            kirby.Name = "Kirby";

            Dog jack = new Dog();
            jack.Name = "Jack";

            // Write a static property
            Dog.Creed = "We are best friends to humans.";

#251 – Class Properties Support the Principle of Encapsulation

Encapsulation is one of the core principles of object-oriented programming.  Encapsulation is the idea of hiding implementation details of a class from the users of that class and only exposing a public interface.

Class properties in C# support the idea of encapsulation.  Client code that wants to read or write a property has access only to its public interface–the data type of the property and the knowledge that there is a get or a set accessor (or both) for that property.

Client code that reads or writes a property has no information about:

  • How the class actually stores the property data
  • The implementation of the get accessor–how data is retrieved when a client reads the property value
  • The implementation of the set accessor–how data is stored when a client writes the property value

#246 – Implementing a Read-Only Property

You implement a read-only property in a class by implementing the get accessor, but not the set accessor.  This will allow client code to read the property’s value, but not write to it directly.

Below is an example of a read-only property for the Dog class.  The WhenLastBarked property returns a DateTime value indicating the last time that the Dog barked–i.e. the last time that someone called the Bark method.

    // Backing variable storing date/time last barked
    private DateTime lastBarked;

    // Public property, allows reading lastBarked
    public DateTime WhenLastBarked
    {
        get
        {
            return lastBarked;
        }
    }

    // Bark method also sets lastBarked
    public void Bark()
    {
        Console.WriteLine("{0}: Woof!", Name);
        lastBarked = DateTime.Now;
    }

We now have a property in the Dog class that we can read from, but not write to.

    kirby.Bark();
    DateTime whenHeBarked = kirby.WhenLastBarked;

#242 – Declaring and Using a Property in a Class

You can create instance data in a class by defining public fields.  You can read and write fields using a reference to an instance of the class.

A class more often exposes its instance data using properties, rather than fields.  A property looks like a field from outside the class–it allows you to read and write a value using a reference to the object.  But internally in the class, a property just wraps a private field, which is not visible from outside the class.

    public class Dog
    {
        // Private field, stores the dog's name
        private string name;

        // Public property, provides a way to access
        // the dog's name from outside the class
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

    }

Using the property:

            Dog kirby = new Dog();

            kirby.Name = "Kirby";

#232 – Declaring and Using Instance Methods in a Class

In a class, an instance method is a kind of class member that is a block of statements that will execute when a user of the class calls the method.  It typically acts upon the data stored in that particular instance of the class.

A method has a return value that allows the method to return a result, or a return type of void, indicating that it doesn’t return any result.

Here’s a simple example of a method:

    public class Dog
    {
        public string Name;
        public int Age;

        public void BarkYourAge()
        {
            for (int i = 1; i <= Age; i++)
                Console.WriteLine("Woof");
        }
    }

Calling our method:

    Dog rover = new Dog();
    rover.Name = "Rover";
    rover.Age = 3;

    rover.BarkYourAge();

The result:

#231 – Declaring and Using Instance Fields in a Class

In a class, an instance field is a kind of class member that is a variable declared in the class and having a particular type.  There is one copy of the field for each instance of the class.  You can read and write the value of the field using a reference to the instance of the class.

Fields are declared in a class as follows:

    public class Dog
    {
        public string Name;
        public int Age;
    }

These fields can then be used as follows:

            Dog buster = new Dog();  // Create new instance of Dog
            buster.Name = "Buster";  // Write to Name field
            buster.Age = 3;          // Write to Age field

            Dog kirby = new Dog();   // Another instance of a Dog
            kirby.Name = "Kirby";
            kirby.Age = 13;

            // Reading properties
            int agesAdded = buster.Age + kirby.Age;