17

Possible Duplicate:
C# optional parameters on overridden methods

This is the output of the following code:

Peter: -1
Peter: 0
Fred: 1
Fred: 1

Can you explain me why the call of Peter p.TellYourAge() and p.DoSomething() is not identical?

Here the code to try it yourself (VS2010 and FW 4):

    static void Main(string[] args)
    {
        Peter p = new Peter();
        p.TellYourAge(); // expected -1, result: -1
        p.DoSomething(); // expected -1, result: 0

        Fred f = new Fred();
        f.TellYourAge(1); // expected 1, result: 1
        f.DoSomething(); // expected 1, result: 1

        Console.ReadKey();
    }
}

public abstract class Person
{
    public abstract void TellYourAge(int age); // abstract method without default value
}

public class Peter : Person
{
    public override void TellYourAge(int age = -1) // override with default value
    {
        Console.WriteLine("Peter: " + age);
    }

    public void DoSomething()
    {
        TellYourAge();
    }
}

public class Fred : Person
{
    public override void TellYourAge(int age) // override without default value
    {
        Console.WriteLine("Fred: " + age);
    }

    public void DoSomething()
    {
        TellYourAge(1);
    }
}
Community
  • 1
  • 1
X181
  • 753
  • 1
  • 5
  • 12
  • 2
    My first guess is that since int is not nullable here: public override void TellYourAge(int age = -1) // override with default value, it's default is always 0... – mservidio Mar 05 '12 at 15:26
  • 2
    @mservidio But that's why you specify the default value – Oskar Kjellin Mar 05 '12 at 15:28
  • 1
    You might be interested in [this article](http://blogs.msdn.com/b/ericlippert/archive/2011/05/09/optional-argument-corner-cases-part-one.aspx) by Eric Lippert. Although it doesn't describe the exact same case, it should give you some clues about what's happening. – Thomas Levesque Mar 05 '12 at 15:29
  • If you use this.TellYourAge() you get -1, but thats not the answer to your question. I'm confused whats happning behind the scene. – Simon Edström Mar 05 '12 at 15:30
  • 1
    Crack open Resharper/ILSpy and see what has been compiled. – Oded Mar 05 '12 at 15:30
  • 6
    See http://stackoverflow.com/questions/8909811/c-sharp-optional-parameters-on-overridden-methods – Sean U Mar 05 '12 at 15:30
  • Note that this triggers the ReSharper code inspection 'Mismatch optional parameter value in overridden method', which the default settings classify as 'warning' level. – AakashM Mar 05 '12 at 15:34
  • 1
    With mono 2.8 on [ideone](http://ideone.com/HUJHn) I get compile errors: `"No overload for method 'TellYourAge' takes '0' arguments"` for both lines where you call `TellYourAge` with zero arguments. – Magnus Hoff Mar 05 '12 at 16:08

1 Answers1

3

If you happen to use Resharper, it will give you the following warning / notification.

"Optional parameter default value differs from parameter age in base method void TellYourAge(int age)."

Look out when you mix optional parameter values and inheritance. Default parameter values are resolved at compile time, not runtime. The default belongs to the reference type being called. Here it resolves to the Person type and it uses the default value of an integer which is 0, instead of -1.

You can find some information about common pitfalls regarding optional parameters here:

http://geekswithblogs.net/BlackRabbitCoder/archive/2010/06/17/c-optional-parameters---pros-and-pitfalls.aspx

Easy fix if you want to use it this way. Explicitly specify the keyword 'this' when calling the method TellYourAge. This way the desired default value will be determined at compile time.

public void DoSomething()
{
    this.TellYourAge();
}
Christophe Geers
  • 8,564
  • 3
  • 37
  • 53
  • 1
    I would expect a compile error or warning in this case, but that's not the point. That the default parameters are resolved at compile time is also clear, but does not explain why the exactly same call to TellYourAge() on the p-instance results in different output. – X181 Mar 05 '12 at 15:46
  • See also http://blogs.msdn.com/b/ericlippert/archive/2011/05/09/optional-argument-corner-cases-part-one.aspx – Eric Lippert Mar 05 '12 at 15:48
  • 1
    The topics are related, but its not a duplicate. In the other case a specified default value is used. In this case the unspecified default value of the type is used. – X181 Mar 05 '12 at 16:08
  • @X181 I believe it's the very same compiler bug. JonSkeet's answer to the old question even tested this case, where the base class has a mandatory parameter. – CodesInChaos Mar 07 '12 at 17:07