Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# derived classes, overload resolution

Ok, I have an some different objects that are derived from a base class and I've put a bunch of them in a list. I want to loop through the list and push each to a method. I have separate methods with each one's type signature, but the compiler is complaining. Can someone explain why? Is this an opportunity to use Generics, and if so, how?

class Base { }
class Level1 : Base { }
class Level2 : Level1 { }

...

List<Base> oList = new List<Base>();
oList.Add(new Level1());
oList.Add(new Level2());

...

...
foreach(Base o in oList)
{
   DoMethod(o);
}

...

void DoMethod(Level1 item) { }
void DoMethod(Level2 item) { }

What am I doing wrong?

like image 345
end-user Avatar asked Aug 05 '10 20:08

end-user


2 Answers

Overloads are resolved at compile-time - and you don't have a DoMethod(Base item) method - so it can't resolve the call. Leaving the list and the loop out of things, you're effectively writing:

Base o = GetBaseFromSomewhere();
DoMethod(o);

The compiler has to find a method called DoMethod which is applicable for a single argument of type Base. There is no such method, hence the failure.

There are a few options here:

  • As Markos says, you can use dynamic typing in C# 4 to make the C# compiler apply overloading at execution time using the actual type of object that o refers to.
  • You can use the Visitor Pattern to effectively get double dispatch (I'm never really fond of this)
  • You can use as or is:

    Level1 x = o as Level2;
    if (x != null)
    {
        DoMethod(x); // Resolves to DoMethod(Level1)
    } 
    else
    {
        Level2 y = o as Level2;
        if (y != null)
        {
            DoMethod(y); // Resolves to DoMethod(Level2)
        }
    }
    

    Again, this is pretty ugly

  • Redesign what you're doing to be able to use normal inheritance, if possible
like image 97
Jon Skeet Avatar answered Sep 18 '22 05:09

Jon Skeet


Overloading a method uses the static type of the variable not the run time type.

You want to use inheritence and overriding.

class Base { public virtual void DoMethod() { /* ... */  } }
class Level1 : Base { public override void DoMethod() { /* ... */ } }
class Level2 : Level1 { public override void DoMethod() { /* ... */ } }
like image 23
Mark Byers Avatar answered Sep 19 '22 05:09

Mark Byers