Method Overloading VS Optional Parameter in C# 4.0

method overloading vs optional parameter in C# 4.0

One good use case for 'Optional parameters' in conjunction with 'Named Parameters' in C# 4.0 is that it presents us with an elegant alternative to method overloading where you overload method based on the number of parameters.

For example say you want a method foo to be be called/used like so, foo(), foo(1), foo(1,2), foo(1,2, "hello"). With method overloading you would implement the solution like this,

///Base foo method
public void DoFoo(int a, long b, string c)
{
//Do something
}

/// Foo with 2 params only
public void DoFoo(int a, long b)
{
/// ....
DoFoo(a, b, "Hello");
}

public void DoFoo(int a)
{
///....
DoFoo(a, 23, "Hello");
}

.....

With optional parameters in C# 4.0 you would implement the use case like the following,

public void DoFoo(int a = 10, long b = 23, string c = "Hello")

Then you could use the method like so - Note the use of named parameter -

DoFoo(c:"Hello There, John Doe")

This call takes parameter a value as 10 and parameter b as 23.
Another variant of this call - notice you don't need to set the parameter values in the order as they appear in the method signature, the named parameter makes the value explicit.

DoFoo(c:"hello again", a:100) 

Another benefit of using named parameter is that it greatly enhances readability and thus code maintenance of optional parameter methods.

Note how one method pretty much makes redundant having to define 3 or more methods in method overloading. This I have found is a good use case for using optional parameter in conjunction with named parameters.

Should you declare methods using overloads or optional parameters in C# 4.0?

I'd consider the following:

  • Do you need your code to be used from languages which don't support optional parameters? If so, consider including the overloads.
  • Do you have any members on your team who violently oppose optional parameters? (Sometimes it's easier to live with a decision you don't like than to argue the case.)
  • Are you confident that your defaults won't change between builds of your code, or if they might, will your callers be okay with that?

I haven't checked how the defaults are going to work, but I'd assume that the default values will be baked into the calling code, much the same as references to const fields. That's usually okay - changes to a default value are pretty significant anyway - but those are the things to consider.

Method Overloading Versus Optional Parameters

I would favour method overloading. There are known versioning issues with optional parameters.

There is a very good article by Jon Skeet here.

Motivation for adding this was making it easier to talk to COM where methods can have many many parameters and less fora new design practice for C# classes

C# Optional Parameters or Method Overload?

Optional parameters are nice, but should be used when it makes sense. Optional parameters often muddy the intent of the method -- If there is another alternative I would lean towards the alternative.

Part of the need for optional parameters and named parameters is because COM allowed optional and name parameters:

MSDN

Some APIs, most notably COM interfaces
such as the Office automation APIs,
are written specifically with named
and optional parameters in mind. Up
until now it has been very painful to
call into these APIs from C#, with
sometimes as many as thirty arguments
having to be explicitly passed, most
of which have reasonable default
values and could be omitted.

SomeNewKid from forums.asp.net puts succinctly:

http://forums.asp.net/t/386604.aspx/1

...overloaded methods are generally
preferable to optional parameters.
Why? To keep each of your methods
clear in purpose. That is, each method
should do one thing well. As soon as
you introduce optional parameters, you
are diluting the cleanliness of that
method, and introducing branching
logic that is probably best kept out
of a method. This clarity of purpose
becomes even more important when you
start using inheritance. If you
override a method that has one or more
optional parameters, they become
harder to work with. So, I'd suggest
that for anything other than quick and
dirty classes, you use overloading in
preference to optional parameters.

Keep in mind that optional parameters are a syntactical sugar:

Reflector C#:

public class Class1
{
// Methods
public Class1()
{
this.Method1("3", "23");
}

public void Method1(string one, [Optional, DefaultParameterValue("23")] string two)
{
}
}

IL:

.class public auto ansi beforefieldinit Class1
extends [mscorlib]System.Object
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: call instance void [mscorlib]System.Object::.ctor()
L_0006: nop
L_0007: nop
L_0008: ldarg.0
L_0009: ldstr "3"
L_000e: ldstr "23"
L_0013: call instance void WebApplication1.Class1::Method1(string, string)
L_0018: nop
L_0019: nop
L_001a: ret
}

.method public hidebysig instance void Method1(string one, [opt] string two) cil managed
{
.param [2] = string('23')
.maxstack 8
L_0000: nop
L_0001: ret
}

}

Performance differences between overloading or optional parameters?

I just did a quick test and the compiler optimizes the code. This basic example Main method.

public static void OptionalParamMethod(bool input, string input2 = null)
{
}

public static void Main(string[] args)
{
OptionalParamMethod(true);
OptionalParamMethod(false, "hello");
}

Compiles to this so the optional params are filled in by the compiler.

public static void Main(string[] args)
{
OptionalParamMethod(true, null);
OptionalParamMethod(false, "hello");
}

As for performance you could argue optional parameters have a slight advantage as there is only a single method call rather than chained method calls like you would normally have for an overloaded method. The code below is compiled output to show what I am talking about. The difference is quite academic though and I doubt you would ever notice in practice.

public static void Main(string[] args)
{
OptionalParamMethod(true, null);
OptionalParamMethod(false, "hello");
OverloadParamMethod(true);
OverloadParamMethod(false, "hello");
}

public static void OptionalParamMethod(bool input, [Optional, DefaultParameterValue(null)] string input2)
{
Console.WriteLine("OptionalParamMethod");
}

public static void OverloadParamMethod(bool input)
{
OverloadParamMethod(input, null);
}

public static void OverloadParamMethod(bool input, string input2)
{
Console.WriteLine("OverloadParamMethod");
}

Conflicting overloaded methods with optional parameters

From MSDN:

If two candidates are judged to be equally good, preference goes to a candidate that does not have optional parameters for which arguments were omitted in the call. This is a consequence of a general preference in overload resolution for candidates that have fewer parameters.

Does C# 4.0 and a combination of optional parameters and overloads give you a warning about ambiguity?

It will compile without warnings and will choose the first overload.

With the introduction of optional and named parameters, the overload resolution mechanism of C# has become really complicated. In this specific case, it makes sense however. As usual, the compiler will choose the most specific overload that matches the arguments.

I don't believe this specific case is much different from C# 1.0:

public void SomeMethod(Int32 x, Int32 y) { } 
public void SomeMethod(Int32 x, Int32 y, params Int32[] z) { }

which works identically (in terms of overload resolution).

Follow up answer: I don't think so. I'm afraid you'll have to manually specify the default argument in the method call. However, if x or y parameter had a different name like:

public void SomeMethod(Int32 x, Int32 y) { } 
public void SomeMethod(Int32 t, Int32 y, Int32 z = 0) { }

you could choose the second overload with:

obj.SomeMethod(t: 10, y: 20);


Related Topics



Leave a reply



Submit