Optional Parameters in C#

Optional parameters in C# allow a method parameter to have a default value. When calling the method, the caller can either provide that argument or leave it out. If the argument is omitted, C# uses the default value defined in the method declaration.

This feature is useful when a method has a common default behavior but also allows customization. Optional parameters can reduce the need for several small overloads, but they must be used carefully because they become part of the method contract.


What Are Optional Parameters in C#?

An optional parameter is a method parameter with a default value assigned in the method declaration. If the caller does not pass a value for that parameter, the default value is used.

void PrintMessage(string message = "Hello")
{
    Console.WriteLine(message);
}

PrintMessage();
PrintMessage("Welcome to C#");

The first call prints Hello because no argument is passed. The second call prints the custom message because an argument is provided.

Syntax of Optional Parameters

returnType MethodName(type requiredParameter, type optionalParameter = defaultValue)
{
    // method body
}

The default value is written after the parameter name using the assignment operator. Optional parameters must have compile-time constant default values, or values such as null, default, or constants that the compiler can embed.

Simple Example of Optional Parameters

Optional parameters are commonly used for settings that usually have a standard value.

decimal CalculateTotal(decimal price, int quantity = 1)
{
    return price * quantity;
}

Console.WriteLine(CalculateTotal(500));
Console.WriteLine(CalculateTotal(500, 3));

The first call uses the default quantity of 1. The second call passes 3, so the default is ignored.

Rules for Optional Parameters

  • Optional parameters must appear after required parameters.
  • Each optional parameter must have a default value.
  • The default value must be known at compile time.
  • Optional parameters can be used with methods, constructors, indexers, and delegates.
  • Named arguments can be used to skip earlier optional parameters and set later ones.

The most important rule is that required parameters come first. This keeps method calls unambiguous when arguments are omitted.

Multiple Optional Parameters

A method can have more than one optional parameter. This is useful when a method has several settings with reasonable defaults.

void CreateUser(string name, bool isActive = true, string role = "User")
{
    Console.WriteLine($"{name}, Active: {isActive}, Role: {role}");
}

CreateUser("Asha");
CreateUser("Ravi", false);
CreateUser("Meera", true, "Admin");

The method can be called with only the required name, or with additional values when the default behavior should change.

Optional Parameters with Named Arguments

Named arguments are very useful with optional parameters because they let you pass only the optional value you care about. This improves readability when there are multiple optional parameters.

CreateUser("Kiran", role: "Manager");

Here, isActive still uses its default value of true, while role is explicitly set to Manager. Without named arguments, skipping the middle optional parameter would not be clean.

Optional Parameters vs Method Overloading

FeatureOptional ParametersMethod Overloading
PurposeProvide default valuesProvide different method signatures
Best forSmall variations in settingsDifferent input shapes or behavior
ReadabilityGood with named argumentsGood when each overload is clear
RiskToo many defaults can hide intentToo many overloads can confuse callers

Use optional parameters when the method behavior is mostly the same and only a few settings change. Use overloading when the method has meaningfully different input forms.

Optional Parameters in Constructors

Constructors can also use optional parameters. This can make object creation shorter when some values have defaults.

class Product
{
    public string Name { get; }
    public decimal Price { get; }

    public Product(string name, decimal price = 0)
    {
        Name = name;
        Price = price;
    }
}

The constructor can be called with only a name, or with both name and price. This is useful for simple models, but complex object creation may need clearer constructors or factory methods.

Versioning Problem with Optional Parameters

Optional parameter default values are baked into the calling code at compile time. This matters for libraries. If a library changes the default value later, existing compiled callers may still use the old default until they are recompiled.

For internal application code, this is usually not a big issue. For public libraries and shared packages, changing optional parameter defaults can create surprising behavior. In those cases, overloads or options objects may be safer.

Compile-Time Defaults

The default value of an optional parameter must be available at compile time. This means you can use literals such as 10, true, "Guest", null, default, or a constant. You cannot use a value that must be calculated at runtime.

const int DefaultRetryCount = 3;

void RetryOperation(int retryCount = DefaultRetryCount)
{
    Console.WriteLine(retryCount);
}

This works because DefaultRetryCount is a compile-time constant. A normal variable would not be allowed as the default value because it can change while the program runs.

Optional Parameters with Nullable Types

Optional parameters often use null when the method should decide a value internally. This is common when a caller may provide a custom value, but the method can use a calculated default when no value is supplied.

void PrintReport(string title, DateTime? generatedAt = null)
{
    DateTime actualDate = generatedAt ?? DateTime.Now;
    Console.WriteLine($"{title} - {actualDate}");
}

DateTime.Now cannot be used directly as an optional parameter default because it is evaluated at runtime. Using null and resolving it inside the method is the correct approach.

Optional Parameters and API Readability

Optional parameters can make an API pleasant to use, but they can also hide important choices. A call like CreateUser("Asha") is short, but the reader may not know what default role, status, or permissions are being applied. If defaults affect security, money, data deletion, or business-critical behavior, they should be very explicit.

For low-risk settings such as formatting, page size, retry count, or display options, optional parameters are often clean. For high-risk rules, required parameters or named configuration objects are usually better.

Optional Parameters and Overload Ambiguity

Optional parameters can create confusing overload resolution when combined with method overloading. If two methods can both accept the same call, the compiler may choose one based on overload rules, or it may report ambiguity.

void Export(string fileName)
{
    Console.WriteLine("Basic export");
}

void Export(string fileName, bool includeHeaders = true)
{
    Console.WriteLine("Advanced export");
}

This kind of design can confuse callers because Export("data.csv") appears to match both meanings. A cleaner design may use one method with optional parameters or separate method names that explain the difference.

Optional Parameters vs Options Object

If a method has many optional settings, an options object is usually better. It groups related settings into one named type and makes the call easier to extend later.

class EmailOptions
{
    public bool IsHtml { get; set; } = true;
    public bool HighPriority { get; set; } = false;
    public string FromAddress { get; set; } = "noreply@example.com";
}

void SendEmail(string to, string subject, EmailOptions options)
{
    Console.WriteLine($"Sending email to {to}");
}

This is more scalable than a method with many optional Boolean and string parameters. It also reduces mistakes caused by passing values in the wrong position.

Optional Boolean Parameters

Optional Boolean parameters should be used carefully because calls can become unclear. A call like Save(file, true) does not explain what true means. Named arguments help, but sometimes separate methods are better.

SaveFile("report.txt", overwrite: true);

The named argument makes the call readable. Without it, the Boolean value forces the reader to inspect the method declaration.

Optional Parameters in Interfaces and Delegates

Optional parameters can appear in interfaces and delegates too, but they need careful design. The default value belongs to the call site, not to the runtime implementation. If an interface method exposes optional defaults, callers may rely on those defaults as part of the contract.

interface INotifier
{
    void Notify(string message, bool urgent = false);
}

This makes the default urgency part of how callers understand the interface. Changing it later can affect maintainability, especially across separate assemblies.

Optional Parameters and Method Intent

An optional parameter should represent a genuine optional choice. If the caller must understand and decide the value for correct behavior, it should probably be required. Defaults are best when there is one obvious common behavior and the custom value is needed only sometimes.

For example, a retry count of 3 may be a reasonable default. A user role, payment status, or delete confirmation should usually not be hidden behind a quiet default unless the business rule is extremely clear.

Optional Parameters in Public APIs

For public APIs, optional parameters should be used more conservatively than in private application code. Once callers depend on the default values, changing those defaults can be a breaking behavioral change. This is especially important for NuGet packages, shared class libraries, and SDK-style code.

If an API is expected to evolve, method overloads or options objects can be easier to version. They allow new settings to be added without silently changing the meaning of old compiled calls.

In short, optional parameters are best for stable, low-risk defaults that make common calls shorter without hiding important decisions.

Use them deliberately.

That keeps calls readable and predictable.

Always.

Common Mistakes with Optional Parameters

  • Putting optional parameters before required parameters.
  • Using too many optional parameters and making calls unclear.
  • Using optional parameters for values that should be required.
  • Changing default values in shared libraries without considering recompilation.
  • Combining optional parameters and overloads in confusing ways.

Best Practices for Optional Parameters in C#

Use optional parameters for simple defaults, keep the number of optional parameters small, prefer named arguments when skipping values, and avoid using defaults to hide important behavior. If the method starts to look like a configuration system, use an options object instead.


Continue learning C# in order
Follow the topic sequence with the previous and next lesson.