#833 – Some Examples of Anonymous Object Initializers

You create an anonymously-typed object using the object initializer syntax.  The declaration consists of a series of member declarators, each of which can be:

  • A named value (Name = value)
  • A value represented by a named object
            Dog myDog = new Dog("Kirby", 15);
            Dog otherDog = new Dog("Ruby", 3);

            var anon1 = new {Name = "Bob", Age = 49};
            var anon2 = new {DogName = myDog.Name, DogAge = myDog.Age};
            var anon3 = new {Name = "Pi", Value = Math.PI};
            var anon4 = new { Area = CalculateArea(2.0, 3.0) };
            int num = 42;
            var anon5 = new { FavoriteNumber = num, Name = "Arthur" };
            var anon6 = new { Dog = myDog, Owner = new Person("Billy") };
            var anon7 = new { FavNum = anon5, SomeGuy = anon1 };

            var anon8 = new {myDog.Name, myDog.Age};
            var anon9 = new { Math.PI, Math.E };
            string name = "Nelson";
            var anon10 = new { num, name };
            var anon11 = new { myDog, otherDog };
            var anonGroup = new { anon1, anon2, anon3 };

            var anon12 = new { Dog1 = myDog, name };

#832 – The Sequence in Which Finalizers Are Called

When you implement a finalizer, using the destructor syntax, the finalizer needs to always call the finalizer of its base class.  The C# compiler will automatically take care of this, invoking the finalizer of the base class within a finally block to ensure that it gets called.

Because the call to the finalizer of the base class occurs within a finally block, it will get called after all of the code within the derived class’ finalizer has executed.  This means that the sequence in which the finalizers are called is from the most derived class up the inheritance chain.

For example, if Terrier inherits from Dog, code in the Terrier’s finalizer will execute before code in the Dog’s finalizer.

 

 

#831 – Implementing a Copy Constructor in a Derived Class

A copy constructor is a constructor that you can define which initializes an instance of a class based on a different instance of the same class.

If a base class includes a copy constructor, you can add a copy constructor to a derived class, from which you call the copy constructor of the base class.

Here’s an example.

    public class Dog
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public DogCollar Collar { get; set; }

        // Standard constructor
        public Dog(string name, int age)
        {
            Name = name;
            Age = age;
        }

        public Dog(Dog otherDog)
        {
            Name = otherDog.Name;
            Age = otherDog.Age;
            Collar = new DogCollar(otherDog.Collar);
        }
    }

    public class Terrier : Dog
    {
        public double GrowlFactor { get; set; }

        public Terrier(string name, int age, double growlFactor)
            : base(name, age)
        {
            GrowlFactor = growlFactor;
        }

        public Terrier(Terrier otherTerrier)
            : base(otherTerrier)
        {
            GrowlFactor = otherTerrier.GrowlFactor;
        }
    }

#830 – The Problem with ICloneable

The ICloneable interface in the .NET Framework includes a single Clone method, meant to make a copy of the object it is invoked on, returning the new copy.

The problem with the ICloneable interface is that it gives client code that uses it no information about whether a deep or a shallow copy (or something in between) is going to be done.  Given the ambiguity and the fact that the client doesn’t really know what the contents of the cloned object will be, it’s recommended that you don’t implement ICloneable, but rather design your own interface or methods, where you can make the semantics more clear.

 

#829 – Add Comments to Indicate Shallow vs. Deep Copying

When you include a copy constructor or Clone method in your class, you should let users of your code know whether these operations are doing shallow or deep copies.

You can indicate whether the copy operation is shallow or deep using XML Documentation Comments.  These comments will then be exposed to Intellisense and within the Object Browser in Visual Studio.  (Provided that you have access to the source code).

For example:

    public class Dog
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public DogCollar Collar { get; set; }

        // Standard constructor
        public Dog(string name, int age)
        {
            Name = name;
            Age = age;
        }

        /// <summary>
        /// Make a (deep) copy of specified Dog
        /// </summary>
        /// <param name="otherDog">Dog to copy</param>
        public Dog(Dog otherDog)
        {
            Name = otherDog.Name;
            Age = otherDog.Age;
            Collar = new DogCollar(otherDog.Collar);
        }
    }

Intellisense will now show this comment:
829-001
As will the Object Browser:

829-002

#828 – Implementing Both a Copy Constructor and ICloneable

A copy constructor is a constructor that creates a new object by making a copy of an existing object.  ICloneable is a standard interface that you can implement, whereby you’ll add a Clone method to your class.  The purpose of the Clone method is to make a copy of the existing object.

Neither a copy constructor nor the ICloneable interface dictates whether you make a shallow or a deep copy of an object.

Your class can implement both methods for making a copy of an object.

    public class Dog : ICloneable
    {
        public string Name { get; set; }
        public int Age { get; set; }

        // Standard constructor
        public Dog(string name, int age)
        {
            Name = name;
            Age = age;
        }

        // Copy constructor (shallow copy)
        public Dog(Dog otherDog)
        {
            Name = otherDog.Name;
            Age = otherDog.Age;
        }

        // ICloneable
        public object Clone()
        {
            return new Dog(this);
        }
    }

#827 – Making a Deep Copy with a Copy Constructor

The semantics that you use within a copy constructor can be to make a shallow copy of an object or a deep copy.

In the example below, the copy constructor for Dog makes a deep copy of the object passed in.  In this case, that means that the new Dog that is created will also have a new instance of DogCollar object, copied from the DogCollar property of the original Dog object.

    public class Dog
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public DogCollar Collar { get; set; }

        // Constructor that takes individual property values
        public Dog(string name, int age)
        {
            Name = name;
            Age = age;
        }

        // Copy constructor (deep copy)
        public Dog(Dog otherDog)
        {
            Name = otherDog.Name;
            Age = otherDog.Age;

            Collar = (otherDog.Collar != null) ?
                new DogCollar(otherDog.Collar.Length, otherDog.Collar.Width) :
                null;
        }
    }

#826 – Deep Copies

When making a copy of an object, you can either make a shallow copy or a deep copy.  As opposed to a shallow copy, a deep copy is one in which a copy is made not only of the top-level object, but of all the objects referenced by the original object.

During the copy process, whenever a reference to a child object is encountered, a new instance (or deep copy) of the child object is made.

For example, if a Dog object contains a reference to a DogCollar object and we make a deep copy, we get the following:

826-001

When doing a deep copy, a deep copy is typically made of all child objects in the object hierarchy.  For example, if the DogCollar instance had in turn referred to another object, a copy would have been made of that object.

#825 – Shallow Copies

When making a copy of an object, you can either make a shallow copy or a deep copy.  A shallow copy is one in which the exact values of all data members of the object are copied.  You can think of this as byte-for-byte copy of the original object.

With a shallow copy, reference-typed members are copied by copying the reference to the object, rather than by making a new copy of the child object.

For example, if a Dog object contains a reference to a DogCollar object and we make a shallow copy, we get the following:

825-001

The problem with a shallow copy is that the second object is now referencing the sub-objects that the first object pointed to.  In many cases, this may not be what you want.  In the example above, if we change the first dog’s collar, we also change the second dog’s collar.

#824 – A Copy Constructor Makes a Copy of an Existing Object

A copy constructor is a constructor that you can define which initializes an instance of a class based on a different instance of the same class.

In the example below, we define a copy constructor for Dog.  The constructor creates a new instance of a Dog based on an existing instance.

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

        // Constructor that takes individual property values
        public Dog(string name, int age)
        {
            Name = name;
            Age = age;
        }

        // Copy constructor
        public Dog(Dog otherDog)
        {
            Name = otherDog.Name;
            Age = otherDog.Age;
        }
    }

Example of using the copy constructor:

            // Create a dog
            Dog myDog = new Dog("Kirby", 15);

            // Create a copy of Kirby
            Dog other = new Dog(myDog);

824-001