When a class defines multiple constructors, it is common to package up data validation and member assignments into the constructor defining the greatest number of arguments (sometimes called the ‘master constructor’). When you do so, you can simplify the maintenance of the type, in that all the core startup logic is isolated, and can be easily updated as business rules change. The remaining constructors of the class can simply “Pass the buck” to the master, supplying any missing values. Consider the following class definition:
Code Snippet
- class Motorcycle
- {
- public int driverIntensity;
- public string driverName;
-
- // Constructor chaining.
- public Motorcycle()
- {
- Console.WriteLine("In default ctor");
- }
-
- public Motorcycle(int intensity)
- : this(intensity, "")
- {
- Console.WriteLine("In ctor taking an int");
- }
-
- public Motorcycle(string name)
- : this(0, name)
- {
- Console.WriteLine("In ctor taking a string");
- }
-
- // This is the 'master' constructor that does all the real work.
- public Motorcycle(int intensity, string name)
- {
- Console.WriteLine("In master ctor ");
- if (intensity > 10)
- {
- intensity = 10;
- }
- driverIntensity = intensity;
- driverName = name;
- }
- }
The nice thing about using constructor chaining, is that this programming pattern will work with any version of the C# language and .NET platform. However, if you are targeting .NET 4.0 and higher, you can further simplify your programming tasks by making use of optional arguments as an alternative to traditional constructor chaining.
Optional arguments allow you to define supplied default values to incoming arguments. If the caller is happy with these defaults, they are not required to specify a unique value, however they may do so to provide the object with custom data. Consider the following version of Motorcycle which now provides a number of ways to construct objects using a single constructor definition:
Code Snippet
- class Motorcycle
- {
- ...
- // Single constructor using optional args.
- public Motorcycle(int intensity = 0, string name = "")
- {
- if (intensity > 10)
- {
- intensity = 10;
- }
- driverIntensity = intensity;
- driverName = name;
- }
- }
With this one constructor, you are now able to create a new Motorcycle object using zero, one or two arguments. Recall that named argument syntax allows you to essentially 'skip' over acceptable default settings.
Code Snippet
- static void MakeSomeBikes()
- {
- // driverName = "", driverIntensity = 0
- Motorcycle m1 = new Motorcycle();
- Console.WriteLine("Name= {0}, Intensity= {1}",
- m1.driverName, m1.driverIntensity);
-
- // driverName = "Tiny", driverIntensity = 0
- Motorcycle m2 = new Motorcycle(name:"Tiny");
- Console.WriteLine("Name= {0}, Intensity= {1}",
- m2.driverName, m2.driverIntensity);
-
- // driverName = "", driverIntensity = 7
- Motorcycle m3 = new Motorcycle(7);
- Console.WriteLine("Name= {0}, Intensity= {1}",
- m3.driverName, m3.driverIntensity);
- }
While the use of optional / named arguments is a very slick way to streamline how you define the set of constructors used by a given class, do always remember that this syntax will lock you into compiling your software under C# 2010 and running your code under .NET 4.0. If you need to build classes which can run under any version of the .NET platform, it is best to stick to classical 'constructor chaining' techniques.
6446a89a-081a-4c79-9978-2824fa0f067b|6|4.8