In an abstract class

public abstract class base
    {
        abstract public int Func(bool flag = true);
    }

I made a change in the derived version:

public class derived : base
    {
        public override int Func(bool flag = false){}
    }

Debugging shows the compiler uses true as default. I expected otherwise, why does it behave thus?

有帮助吗?

解决方案

This behavior is stated in the C# language specification at §7.5.1.1 (Corresponding Parameters, emphasis mine):

For each argument in an argument list there has to be a corresponding parameter in the function member or delegate being invoked. The parameter list used in the following is determined as follows:

  • For virtual methods and indexers defined in classes, the parameter list is picked from the most specific declaration or override of the function member, starting with the static type of the receiver, and searching through its base classes

During binding (the process of associating the method to call to an invocation) the compiler finds a list of arguments using the rules stated above then a set of candidate methods conforming to that argument list. Among these the best one is picked and bound to the invocation.
Take this code:

BaseClass b = new DerivedClass( );
b.Func( );

During binding the argument list used is the one declared in BaseClass.Func (because that is the static type of b) and the set of candidate methods is BaseClass.Func and DerivedClass.Func (they are said to be applicable, because both argument list correspond to the one chosen). Then DerivedClass.Func is decided to be the best candidate, as expected, and therefore bound to the call using the parameter list of BaseClass.Func, thus using flag = true.

You can find more details in §7.5.3 (Overload resolution). Finally, in case you wonder, abstract methods are considered virtual, as noted in §10.6.6 (Abstract methods):

An abstract method declaration introduces a new virtual method but does not provide an implementation of that method.

其他提示

I've created a sample that mimics your situation. Long story short: which default value is used depends on whether you access the instance by a variable of the type of the base class or the derived class. So the compiler detects the default value of the optional parameter based on the type of variable. This makes sense as you could store any instance of a derived class in the variable (polymorphism). It might not even be clear at compile time, which the type if instance is (e.g. if you configure your system to use a specific type). All the compiler knows is the type of the variable and that any instance that you put into it in a type-safe manner offers the same interface.

using System;

public abstract class MyBase
{
    public abstract bool GetValue(bool value = true);
}

public class MyDerived : MyBase
{
    public override bool GetValue(bool value = false)
    {
        return value;
    }
}

public class Test
{
    public static void Main()
    {
        var derived = new MyDerived();
        Console.WriteLine("Value = {0}", derived.GetValue());
        MyBase myBase = derived;
        Console.WriteLine("Value = {0}", myBase.GetValue());
    }
}

I assume that you call the method on a variable of the type of the base class which would explain the behavior.
Basically, this resembles the behavior if you don't override the method but shadow it. It is a situation you will want to avoid in almost all circumstances because the risk that the code will not behave in the way you expect it is relatively high.
Therefore I'd suggest to get rid of the optional parameters and make them required ones (and maybe create an overload without the parameter). Having to type less and being able to change the default value later is not worth the risk of having a unexpected behavior of your code. The behavior might be transparent to you now, but I doubt that it will be some months later or to coworkers of yours that have to maintain the code.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top