#690 – Using the this Keyword To Distinguish Between Fields and Parameters

The this keyword refers to the current instance of a particular class.

One common use for the this keyword is to qualify a variable name, indicating that the name in question is a member of the class.

In the example below, we have two properties in a class that have the same name as parameters passed in to a constructor.  We want to assign the value of the parameters to the properties.  But the compiler doesn’t know which name or age we mean in the assignment statements.  (Notice the warning).

We can clear up the confusion by prefixing the property names with the this keyword.

        public string name { get; set; }
        public int age { get; set; }

        public Dog(string name, int age)
        {
            this.name = name;
            this.age = age;
        }

You could also use a naming convention to avoid the confusion, e.g. make the property names capitalized.

#689 – References and Objects

A variable whose type is a reference type can be declared without making the variable point to an instance of that type (an object).  At this point, the value of the variable will be null.

A reference-typed variable can later be assigned to refer to an instance of the appropriate type, or it can be assigned at the point where it is declared.

            Dog myDog;
            myDog = new Dog("Kirby", 13);

            Dog yourDog = new Dog("Ruby", 2);

A reference-typed variable can be re-assigned to refer to a difference instance of the type.  (If an object is no longer referenced by any variables, it will eventually be garbage collected).

            Dog jack = new Dog("Jack", 15);
            Dog kirby = new Dog("Kirby", 13);

            Dog currentDog = jack;
            currentDog = kirby;

Notice also in this example that more than one reference-typed variable can refer to the same object.

#688 – Aggregation, Composition and Containment

The idea of containment in object-oriented programming is the idea that an outer class contains an instance of another class and allows access to the contained object through its own methods.

Aggregation is one form of containment where the contained object can exist independently from the outer object.  For example, a Family object might contain an instance of a Dog object, representing a dog that the family owns.

    public class Family
    {
        List<Dog> OurDog { get; set; }

        void AcquireDog(Dog d)
        {
            OurDog.Add(d);
        }
    }

Composition is a type of containment where the contained object is created and exists entirely within the object that contains it.  It ceases to exist when the containing object is destroyed.  For example a Dog is composed of an instance of a DogName object (among other things).  You can’t have an instance of a DogName without a Dog.

#687 – An Example of Containment

One common strategy is to use inheritance when modeling an is-a type of relationship (e.g. a Terrier is-a Dog) and to use containment when modeling a has-a type of relationship (e.g. a Family has-a Dog).

Here’s an example of containment, where a Dog object contains instances of the DogName and DogAbilities classes.

    internal class DogName
    {
        public DogName(string humanName, string nameInDogWorld)
        {
            HumanName = humanName;
            NameInDogWorld = nameInDogWorld;
        }

        public string HumanName { get; set; }
        public string NameInDogWorld { get; set; }
    }

    internal class DogAbilities
    {
        public DogAbilities(List<string> knownTricks, bool canBark)
        {
            KnownTricks = knownTricks;
            CanBark = canBark;
        }

        public List<string> KnownTricks { get; set; }
        public bool CanBark { get; set; }
    }

    public class Dog
    {
        public Dog(string humanName, string firstTrick, bool canBark)
        {
            Name = new DogName(humanName, GenerateSecretDogWorldName());

            List<string> abilities = new List<string>();
            abilities.Add(firstTrick);

            Abilities = new DogAbilities(abilities, canBark);
        }

        public void Bark()
        {
            if (Abilities.CanBark)
                Console.WriteLine("Woof!");
            else
                Console.WriteLine("Wag");
        }

        public void DoTrick(string trick)
        {
            if (Abilities.KnownTricks.Contains(trick))
                Console.WriteLine("Doing {0} trick", trick);
        }

        public void TeachTrick(string newTrick)
        {
            if (!Abilities.KnownTricks.Contains(newTrick))
                Abilities.KnownTricks.Add(newTrick);
        }

        private DogName Name { get; set; }
        private DogAbilities Abilities { get; set; }

        private string GenerateSecretDogWorldName()
        {
            return "His noble woofiness sir poops-a-lot";
        }
    }

#686 – Inheritance vs. Containment

You can think of inheritance as white box reuse of existing code, meaning that a derived class can see some aspects of the internals of the base class.  This violates the principle of encapsulation, which states that the implementation details of a class are hidden from any code that uses the class.

There is another method of code reuse known as containment, which results in black box reuse of existing code.  Instead of deriving from a base class, the new class just creates an instance of the class internally and accesses only the public members of the instance.  The instance of the base class can be thought of as a black box, because the derived class doesn’t have access to the implementation details of the base class.

#685 – Inheritance Can Break Encapsulation

Recall that inheritance and encapsulation are two of the core principles of object-oriented programming.  Encapsulation is the idea of hiding implementation details of a class from code that lives outside the class.  Inheritance is the idea that a class can derive from a parent classs, inheriting data and behavior.

Inheritance increases the coupling between the derived and base classes.  Coupling is the degree to which one class depends on the implementation of another.  Changes in the base class are likely to affect the behavior of the derived class.

Inheritance increases coupling because the derived class obtains access to protected data in the parent class and because it can override behavior in the parent class.  This violates the idea of encapsulation, because the child class can see implementation details in the base class.

#684 – Hidden Base Class Members Aren’t Really Hidden

When authoring a derived class, you can hide a member of the base class using the new keyword.  For a method, this indicates that the method in your derived class replaces the method in the base class and will be called when invoked on objects of the derived type.  (It also means that the method will not behave polymorphically).

    public class Dog
    {
        public virtual void Bark()
        {
            Console.WriteLine("Dog: Woof");
        }
    }

    public class Terrier : Dog
    {
        public new void Bark()
        {
            Console.WriteLine("Terrier: Yip yip");
        }
    }

However, if you have an instance of the derived class and cast it to the type of its base class, you’ll end up accessing the method in the base class after all.

            Terrier t = new Terrier();

            t.Bark();         // Yip yip

            ((Dog)t).Bark();  // Woof