#816 – Named Argument and Optional Parameter Combinations

You use named arguments (vs. positional) to reverse the order of arguments passed in to a method when you call it.

You use optional parameters (vs. required) to to allow omitting an argument for that parameter when you call the method.

Options include:

  • No named arguments, no optional parameters – you must pass in a value for each parameter, in the proper order
  • Named arguments only – you must pass in an argument for each parameter, but you can change the order of the arguments.  Named arguments must follow positional arguments.
  • Optional parameters only – you must pass arguments in the correct order, but may omit one or more arguments if the corresponding parameter is optional.  If you omit an argument for one parameter, you must omit arguments for all parameters that follow that parameter.
  • Named arguments and optional parameters – you can supply any combination of arguments, in any order

#693 – Named Arguments in Constructors Allow the Most Flexibility

If you declare multiple constructors for a class, you can create constructors that support any combination of parameters.

For example:

        public Dog(string name, int age, string favToy)
        {
            // init stuff
        }

        public Dog(string name) : this(name, 1, null) { }
        public Dog(string name, string favToy) : this(name, 1, favToy) { }

Using optional parameters, you can declare a single constructor:

        public Dog(string name, int age = 1, string favToy = null)
        {
            // init stuff
        }

But when you do pass in arguments for any optional parameters, you must pass them in the correct order, without skipping any.

To get around this problem, you can use named arguments when invoking the constructor.

            // Ok to omit age, but then favToy must be named argument
            Dog spot = new Dog("Spot", favToy: "Ball");

#692 – Two Approaches for Optional Parameters in Constructors

When you create an instance of an object, you may want to pass different combinations of parameters for purposes of initializing the object.  In authoring a class, there are a couple different ways to support this.

You can declare multiple constructors, each supporting a different set of parameters.  You can use constructor chaining to invoke the main constructor, to centralize object initialization.

        public Dog(string name, int age, string favToy )
        {
            // Do all parameter validation here
            Name = name;
            Age = age;
            FavoriteToy = favToy;
        }

        public Dog(string name) : this(name, 1, null)
        {
        }

        public Dog(string name, int age) : this(name, age, null)
        {
        }

        public Dog(string name, string favToy) : this(name, 1, favToy)
        {
        }

You can also use optional parameters in a single constructor, to do the same thing.

        public Dog(string name, int age = 1, string favToy = null)
        {
            // Do all parameter validation here
            Name = name;
            Age = age;
            FavoriteToy = favToy;
        }

#594 – When You’d Want to Use Named Arguments

You can change the  order of arguments passed to a method in C# by using named arguments.  Simply changing the order of required arguments probably doesn’t make much sense.  Instead, you’ll likely make use of named arguments as a way of omitting optional parameters.

Without named arguments, when you want to include a value for an optional parameter, you normally have to include values for all arguments up to and including the one that you want to specify a value for.  But with named arguments, you can pick and choose which parameters you provide a value for.

Here’s a Dog.Bark method that has several optional parameters.

public void Bark(string barkSound, int numTimesToBark = 1, int volume = 1, string postBarkSound = null)

When calling Bark, we can choose which arguments to pass.

kirby.Bark("Woof", volume: 5);
kirby.Bark("Grrr", postBarkSound: "Arf");
kirby.Bark("Woof", 3, postBarkSound: "Growf");

#592 – Optional Parameters in Indexers

In addition to defining optional parameters within methods, you can also include an optional parameter in an indexer.

For example, assume that we have a Dog class that keeps track of the sounds that a dog makes when he barks and that we’ve defined an indexer for the class that retrieves a “bark sound” from that list.

        public string this[int i]
        {
            get
            {
                return BarkRecord[i];
            }
        }

Using the indexer:

            kirby.Bark("Woof");
            kirby.Bark("Bow-wow");
            kirby.Bark("Urgh");

            Console.WriteLine(kirby[2]);


We can now add an optional parameter to the indexer, to indicate that we’d like the date/time of the bark returned as well.

        public string this[int i, bool includeTime = false]
        {
            get
            {
                string barkInfo = BarkRecord[i];

                if (includeTime)
                    barkInfo = barkInfo + string.Format(" at {0}", BarkTime[i]);

                return barkInfo;
            }
        }

Using the indexer:

            Console.WriteLine("Bark at [2]={0}", kirby[2]);
            Console.WriteLine("Bark at [1]={0}", kirby[1, true]);

#591 – How Optional Parameters Look with Intellisense

When you’re working in Visual Studio and you start typing in the name of a method, Intellisense will show you any optional parameters that the method has.

In the example below, we’ve started entering code to create a new instance of a Dog object.  Intellisense shows us a list of the optional parameters that are defined for the constructor.

#589 – Optional Parameters Must Be Input Parameters

An optional parameter must be an input parameter.  It can’t therefore be modified by the out or ref keywords.  An optional parameter also cannot be modified by the params keyword.

        // OK: numTimesToRead is an input parameter (passed by value)
        static void ReadBook(string title, int numTimesToRead = 1)
        {
        }

        // NO: out parameter can't have default value
        static void ReadBook2(string title, out int yourRating = 3)
        {
            yourRating = 4;
        }

        // NO: ref parameter can't have default value
        static void ReadBook3(string title, ref string yourOpinion = "Unknown")
        {
        }

        // NO: Parameter array can't have default value
        static void ReadBook4(string title, params string[] characters = null)
        {
        }