Derived classes and overloaded methods

R

Random.Coder

The output of this simple program below differs if it's compiled in
Visual Studio 2005 and 2008. Is one the correct output, and if so,
why?

using System;

namespace DerivedTestApp
{
class BaseClass
{
static public void Test(uint a)
{
Console.WriteLine("(BaseClass) uint: {0}", a);
}
}

class DerivedClass : BaseClass
{
public enum TestEnum
{
Alpha,
Beta,
}

static public void Test(TestEnum a)
{
string s = "Error";
switch (a)
{
case TestEnum.Alpha: s = "Alpha"; break;
case TestEnum.Beta: s = "Beta"; break;
}
Console.WriteLine("(DerivedClass) TestEnum: {0}", s);
}
}

class Program
{
static void Main()
{
DerivedClass.Test((uint)0);
DerivedClass.Test(DerivedClass.TestEnum.Alpha);
}
}
}

// -- Visual studio 2005:
//(BaseClass) uint: 0
//(DerivedClass) TestEnum: Alpha
// -- Visual studio 2008:
//(DerivedClass) TestEnum: Alpha
//(DerivedClass) TestEnum: Alpha
 
P

parez

It's a known "breaking change" for VS2008. See http://download.microsoft.com/download/d/7/e/d7eeb256-5789-411c-a367-...

The short answer is (from the above document): "All constant expressions
equal to 0 are now implicitly convertible to enum types"

In other words, even though you cast your 0 to "uint", the compiler is
able to implicitly convert it to an enum type. Since you're calling the
method from the derived class, the compiler prefers the overload found in
that class, and since it can implicitly convert the 0 to the appropriate
enum type now, it does.

Pete

will the same difference be reflected in overloaded functions with
int some1(SomeEnum a)
int some1(uint a)
 
J

Jon Skeet [C# MVP]

Peter Duniho said:
In fact, reviewing the overload resolution rules, I think I might have
been misstating the rule to say that a method in a more-derived class has
precedence.

It's somewhat buried. Basically if an applicable method is *first
declared* (i.e. not overridden) in a more derived class, *all*
applicable methods first declared in base classes are ignored. It leads
to very unintuitive cases, such as this:

using System;

class Base
{
public virtual void Foo(int x)
{
Console.WriteLine("Base.Foo(int)");
}
}

class Derived : Base
{
public override void Foo(int x)
{
Console.WriteLine("Derived.Foo(int)");
}

public void Foo(object x)
{
Console.WriteLine("Derived.Foo(object)");
}
}

class Test
{
static void Main()
{
new Derived().Foo(1);
}
}
 
J

Jon Skeet [C# MVP]

Peter Duniho said:
It's somewhat buried. Basically if an applicable method is *first
declared* (i.e. not overridden) in a more derived class, *all*
applicable methods first declared in base classes are ignored. It leads
to very unintuitive cases, such as this: [snip]

Ahh...so I wasn't just imagining things. And yes, I agree that the
example you showed isn't completely intuitive. I do kind of understand
why the rule is the way it is.

I understand it when there *isn't* an override in the derived class
(otherwise you have a versioning issue if a base class adds an overload
unexpectedly) but when there *is* an override, it's clear that the
derived class knows about the base class's method, so at that point I
see no reason to exclude that signature.
But it's not immediately obvious why it makes sense that the
hierarchy-based rule takes precedence over the "more specific type"
rule.
Right.

Anyway, thanks for the clarification. Good stuff. :)

I'm just glad you haven't asked me where it is in the spec. It's
definitely there somewhere, but it always takes me a while to find!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top