Richard Bos
Richard Bos

Reputation: 813

c# does not choose the function I want it to, based on parameter type(inheritance)

I'm not sure how I can explain this, so I'll just show my example and elaborate.

using System;

namespace Demo
{
    static class Program
    {
        static void Main()
        {
            var test = new ExampleClass(new Bar());

            Console.WriteLine(test);
        }
    }

    class ExampleClass {
        public Foo _foo;

        public ExampleClass(Bar bar)
        {
            _foo = bar;
        }

        public override String ToString() {
            return print(_foo);
        }

        String print(Bar bar) {
            return bar.Name;
        }

        String print(Foo foo) {
            return foo.ToString();
        }
    }

    class Bar : Foo
    {
        public String Name;
    }

    class Foo
    { }
}

Ok so this does not work.

Although I can see the type of _foo is Foo in the declaration, it can also be Bar, since it inherits from Foo.

My question is:

Why doesn't the compiler see the actual type of _foo?

Why is print(Foo) always executed, eventhough the type is a derived class of Foo?

Edited

Edited my example code as it still contained to much of my original code.

Thanks Anthony Pegram for the example.

Upvotes: 2

Views: 211

Answers (3)

Anthony Pegram
Anthony Pegram

Reputation: 126932

Your code does not particulary demonstrate your problem well, because you've introduced a field of type SyntaxNode without showing how it relates to your BaseClass/BaseClassExtension type hierarchy. But there is still something there that can be answered when given understandable types.

My question is: Why doesnt the .net runtime see the actual type of originalNode? Why does it always go to print(BaseClass), eventhough the type is BaseClassExtention?

The .NET runtime is not what is determining which overload to use. This is a property of the compiler, which uses information it has about the type of the variable (or field, property) in order to determine which overload to use.

A simple demonstration. Say we have

class Foo { }
class Bar : Foo { }

void Do(Foo foo)
{
     Console.WriteLine("Foo overload");
}

void Do(Bar bar)
{
    Console.WriteLine("Bar overload");
}

And then you have code

Foo foo = new Bar();
Do(foo);

You have a variable of type Foo that happens to refer to an object of type Bar. The compiler emits code to invoke the Foo overload at compile-time, because that's what it knows, and frankly, that's what you have told it to do. (The fact that we instantiated it to an object of type Bar on the preceding line is not particularly relevant. On the next line, just consider that foo could have come from anywhere, and what we know is that variable foo is of type Foo.)

If you wish to use the more specific overload at runtime, you might explore double-dispatch mechanisms such as the Visitor Pattern. Another approach that I don't particularly recommend is to determine the type at runtime via the dynamic keyword (there are generally better alternatives if the problem is well understood, but sometimes it fits).

Foo foo = new Bar();
Do((dynamic)foo);

The semantics of dynamic at runtime is something you can research in your own time, but this effectively produces the result you seem to desire.

Upvotes: 2

Alexei Levenkov
Alexei Levenkov

Reputation: 100545

It looks like you expected that print will be selected based on run-time type of the originalNode. C# is picking functions to call at compile time - print are not virtual methods so call must be resolved at compile time.

So you have

 public SyntaxNode originalNode;
 string print(BaseClassExtention Class)...
 string print(BaseClass base)...

At compile time one of 2 print functions will be selected (based on if SyntaxNode is BaseClass or BaseClassExtension). If SyntaxNode derives from BaseClassExtension than string print(BaseClassExtention Class) version is used (as it more specific than BaseClass one even both could be used), otherwise the other version.

If you want behavior to be different based on run-time type of originalNode you need to either call some virtual method of originalNode as part of print or manually check type and do something inside of your print method.

Upvotes: 0

Matthew Watson
Matthew Watson

Reputation: 109732

I tried this out, but it works as expected if class SyntaxNode derives from class BaseClassExtention - so it's difficult to tell what the problem is from the code you've shown us.

This works as I'd expect:

using System;

namespace Demo
{
    static class Program
    {
        static void Main()
        {
            var test = new myNode();

            Console.WriteLine(test);
        }
    }

    class myNode
    {
        public SyntaxNode originalNode = new SyntaxNode{Name = "SyntaxNode"};

        public override string ToString()
        {
            return print(originalNode); // This calls print(BaseClassExtention Class)
        }

        string print(BaseClassExtention Class) // <= This gets called.
        {
            return Class.Name;
        }

        string print(BaseClass b)
        {
            return b.ToString();
        }
    }

    class BaseClass
    {}

    class BaseClassExtention : BaseClass
    {
        public string Name { get; set; }
    }

    class SyntaxNode: BaseClassExtention
    {

    }
}

Upvotes: 0

Related Questions