C# Foundations · Lesson 24

Named arguments and optional parameters

Make call sites readable without hiding important choices.

How it works

Named arguments associate a supplied value with a parameter name. They can clarify calls with several values of the same type, especially booleans or numeric thresholds. Optional parameters define values that callers may omit. Together, these features can make a small formatting or calculation API pleasant to use while preserving one implementation of its behavior.

A parameter name becomes part of the source-level calling experience. Renaming a public parameter can therefore break callers that use named arguments even when its position and type stay unchanged. Defaults are also an API policy: an omitted value means that the caller accepts that default, not that the program has discovered the right value from the surrounding environment.

Walk through the example. The Price function accepts a quantity, a unit price, and an optional discount. The first call names the two required parameters in reverse textual order, demonstrating that the names determine their association. The second call supplies a discount explicitly. Invariant formatting makes both decimal totals display with the same two fractional digits.

Watch the boundary. A default parameter value is generally encoded into the caller at compilation. Changing a library's default does not magically rewrite an already compiled client. Avoid using an optional constant for a policy that must be loaded dynamically at every call. For values with subtle meanings, a small options type may be clearer than a long list of optional parameters.

Practice independently. Write a label-building function with a required item name and optional quantity and suffix. Call it with positional arguments, named arguments, and a mixture that follows the language rules. Add a validation rule for negative quantities. Finally compare two APIs: one with an optional tax rate and another that receives an explicit pricing policy. Explain which can safely change its rules at runtime.

A working example

using System;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;

decimal Price(int quantity, decimal unitPrice, decimal discount = 0m) => quantity * unitPrice - discount;
Console.WriteLine(Price(unitPrice: 3.5m, quantity: 2).ToString("F2", CultureInfo.InvariantCulture));
Console.WriteLine(Price(2, 3.5m, discount: 1m).ToString("F2", CultureInfo.InvariantCulture));

Expected output

7.00
6.00
Try this
Use names for ambiguous calls; treat optional defaults as a versioned contract.