Reputation: 813
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
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
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
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