Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Quirks when using overloaded methods with params string[] and inheritance

Tags:

c#

I had a class like this

public class Child
{
    public string ToXml()
    {
        return "Child : ToXml()";
    }

    public string ToXml( params string[] fields )
    {
        return "Child : ToXml(...)";
    }
}

creating an instances of class Child and calling ToXml() returns the first overloaded function which was fine and dandy.

var obj = new Child();
Console.WriteLine( obj.ToXml() );

Output:

Child : ToXml()

But when I added a Parent class and changed the Child class to this :

public class Parent
{
    public virtual string ToXml()
    {
        return "Parent : ToXml()";
    }
}

public class Child : Parent
{
    public override string ToXml()
    {
        return "Child : ToXml()";
    }

    public string ToXml( params string[] fields )
    {
        return "Child : ToXml(...)";
    }
}

The output has changed to this :

Child : ToXml(...)

My question is, why is the behaviour like this? (I'm using VS2010 using .NET 3.5)

I kind of 'fixed' this problem by changing the second overloaded function to this : (I took out the params keyword

public class Child : Parent
{
    public override string ToXml()
    {
        return "Child : ToXml()";
    }

    public string ToXml( string[] fields )
    {
        return "Child : ToXml(...)";
    }
}

Which brings me to my second question (let me know if I should split this to 2 different post), what is the difference between the functions

ToXml( params string[] fields )

and

ToXml( string[] fields )

They both seems to work when I call the functions like so :

var obj = new Child();
Console.WriteLine( obj.ToXml( new [] { "foo", "bar" ) );
like image 740
CodeStig Avatar asked Dec 17 '22 06:12

CodeStig


1 Answers

why is the behaviour like this?

It is not clear what you mean by "like this", so first off, let's characterize the behaviour correctly. The behaviour you are experiencing is: for the purposes of overload resolution, an applicable candidate method on a derived type is always better than an applicable candidate method on a base type. Moreover, a virtual method is considered to be a method of the type which declares it, not the type which overrides it.

It's also not clear what you mean by "why"? "Why" questions are hard to answer; in one sense the question is already answered: why does the compiler exhibit that behaviour? Because that's the consequence of the specified rules for overload resolution tie breaking. But you might then say that the question has been begged; the question now is "so why was the specification written that way?"

The specification was written that way because doing so mitigates the brittle base class problem. The brittle base class problem is the situation where you have two teams, one working on the base class, and one working on the derived class. If the team working on the base class introduces a new method, then doing so should not change the behaviour of code that uses the derived class. If it does, then the base class change has "broken" the derived class behaviour. C# has been carefully designed to mitigate brittle base class problems.

Even leaving the brittle base class problem out of it, it makes sense to prioritize the method on the derived class. The developers of the derived class have more information than the developers of the base class. They know that they've got a Banana in hand; the developers of the base class only know that they have a Fruit. The call should go to the method written by the developers who had more information when possible.

You might then say "well, the question has been begged again; now I want to know why mitigating the brittle base class problem is important". Rather than continue down this infinite regress I'll just leave it at that; if you want to know more, then ask a less vague question.

If the subject of brittle base class failure mitigation interests you, consider reading my lengthy series of articles on it.

what is the difference between the functions

The difference is that one is potentially an applicable candidate in either its expanded form or its normal form, whereas the other one has only one applicable candidate form.

like image 84
Eric Lippert Avatar answered Dec 18 '22 19:12

Eric Lippert