Overloading across inheritance boundaries in c#? - c#

After reading this article & that article - I got confused.
It says :
If there are two methods at different levels of the hierarchy, the
"deeper" one will be chosen first, even if it isn't a "better function
member" for the call.
Also -
It turns out that if you override a base class method in a child
class, that doesn't count as declaring it.
Now let's go back to my question :
Case 1
public class Base
{
public virtual void Foo(int x) { "1".Dump();}
}
public class Child : Base
{
public void Foo(object x) { "3".Dump();}
public override void Foo(int x) { "2".Dump();}
}
void Main()
{
Child c = new Child();
c.Foo(10); //emits 3
}
OK.According to the article
"deeper" one will be chosen first, even if it isn't a "better function. and it doesn't count the override...
So it is right and the program emits "3". ( Foo(object x) is executed)
Let's change line order of 1 line :
Case 2
public class Base
{
public virtual void Foo(int x) { "1".Dump();}
public void Foo(object x) { "3".Dump();} //<line being moved here
}
public class Child : Base
{
public override void Foo(int x) { "2".Dump();}
}
void Main()
{
Child c = new Child();
c.Foo(10); //emits 2 !!!!
}
Now it emits "2".
Now lets change all int to object and all object to int :
Case 3
public class Base
{
public virtual void Foo(object x) { "1".Dump();}
public void Foo(int x) { "3".Dump();}
}
public class Child : Base
{
public override void Foo(object x) { "2".Dump();}
}
void Main()
{
Child c = new Child();
c.Foo(1); //emits "3"
}
Questions :
Question#1 : in case 2 , Child inherited the Foo(object x) from its father AND he also overrides a method.
but didnt we just say that :
It turns out that if you override a base class method in a child
class, that doesn't count as declaring it
???
in fact, we didnt also declared the inherited function ... so what is the rule here in this situation ?
Question#2 : in case 3 , Child inherited the Foo(int x) from its father AND he also overrides a method.
but now , he chooses its father function....
it seems like override is winning only if it has exact match.
again , what is the rule here in this situation ?

See member lookup process of a name N in a type T (in your case member Foo in type Child):
First, the set of all accessible (Section 3.5) members named N declared in T and the base types (Section 7.3.1) of T is constructed:
virtual void Foo(int x) // Base
void Foo(object x) // Base
override void Foo(int x) // Child
Declarations that include an override modifier are excluded from the set.
virtual void Foo(int x) // Base
void Foo(object x) // Base
Argument has an integer type. So, best choice here is (argument type matches parameter type)
virtual void Foo(int x) // Base
And this method called. But it is virtual method. And its invoked due to virtual method invocation mechanism:
For every virtual method declared in or inherited by a class, there
exists a most derived implementation of the method with respect to
that class. The most derived implementation of a virtual method M with
respect to a class R is determined as follows:
If R contains the introducing virtual declaration of M, then this is the most derived implementation of M.
Otherwise, if R contains an override of M, then this is the most derived implementation of M.
Otherwise, the most derived implementation of M with respect to R is the same as the most derived implementation of M with respect to
the direct base class of R.
And what is most derived implementation of virtual void Foo(int x) method with respect to a class Child? Yes, it is
override void Foo(int x) // Child
Which is invoked.
Same rules applied in your third sample. But when two options left after overridden method removing, best choice (due to argument type) is non-virtual method.

There are 2 things happening:
When selecting the method to invoke, the compiler will obey the rules as per the linked articles - ie. a deeper method will be chosen before a shallower one even if the shallower one is a more specific match
If you call an overridden method, it will always call the overridden method (this is separate to selecting which method to call), the "only" way to call the base method is from the subclass and using base.MyMethod(..)
So basically the lookup rules can choose the method taking an int if it's on a deeper class, but when the method gets called, if it's been overridden it will call the method taking an int on the child class.

I think you are just messing up your facts by reading the two articles.. It should behave like any other normal overridden function as there is no overloading in the child class and thus there is nothing to choose from.. Lets take a simple example:
public class A
{
public virtual void Foo()
{
Console.WriteLine("A.Foo() called");
}
}
public class B: A
{
public override void Foo()
{
Console.WriteLine("B.Foo() called");
}
}
void Main()
{
new B().Foo();
}
What is the expected output? Obviously without thinking twice anyones gonna say B.Foo() called. Well in your case the very same thing is happening. It doesnt matter that the base class has a better overloaded method, the child class just wins it.. Dont over-complicate things..
About case 3, I am not totally sure about this one, but what happens here is that the compiler tries the implicit conversion to object and then it finds that there is a deeper method with the same signature and thus the rule
if there are two methods at different levels of the hierarchy, the
"deeper" one will be chosen first, even if it isn't a "better function
member" for the call
and now once it goes to the base class it notices that there is a better method that can be used and hence calls that method..
P.S: The explanation above is based on the results that have been observed and might not necessarily be the exact reasons for the above seen behavior.

Related

Why in this code the output of the virtual functions is like this? [duplicate]

What are differences between declaring a method in a base type "virtual" and then overriding it in a child type using the "override" keyword as opposed to simply using the "new" keyword when declaring the matching method in the child type?
I always find things like this more easily understood with pictures:
Again, taking joseph daigle's code,
public class Foo
{
public /*virtual*/ bool DoSomething() { return false; }
}
public class Bar : Foo
{
public /*override or new*/ bool DoSomething() { return true; }
}
If you then call the code like this:
Foo a = new Bar();
a.DoSomething();
NOTE: The important thing is that our object is actually a Bar, but we are storing it in a variable of type Foo (this is similar to casting it)
Then the result will be as follows, depending on whether you used virtual/override or new when declaring your classes.
The "new" keyword doesn't override, it signifies a new method that has nothing to do with the base class method.
public class Foo
{
public bool DoSomething() { return false; }
}
public class Bar : Foo
{
public new bool DoSomething() { return true; }
}
public class Test
{
public static void Main ()
{
Foo test = new Bar ();
Console.WriteLine (test.DoSomething ());
}
}
This prints false, if you used override it would have printed true.
(Base code taken from Joseph Daigle)
So, if you are doing real polymorphism you SHOULD ALWAYS OVERRIDE. The only place where you need to use "new" is when the method is not related in any way to the base class version.
Here's some code to understand the difference in the behavior of virtual and non-virtual methods:
class A
{
public void foo()
{
Console.WriteLine("A::foo()");
}
public virtual void bar()
{
Console.WriteLine("A::bar()");
}
}
class B : A
{
public new void foo()
{
Console.WriteLine("B::foo()");
}
public override void bar()
{
Console.WriteLine("B::bar()");
}
}
class Program
{
static int Main(string[] args)
{
B b = new B();
A a = b;
a.foo(); // Prints A::foo
b.foo(); // Prints B::foo
a.bar(); // Prints B::bar
b.bar(); // Prints B::bar
return 0;
}
}
The new keyword actually creates a completely new member that only exists on that specific type.
For instance
public class Foo
{
public bool DoSomething() { return false; }
}
public class Bar : Foo
{
public new bool DoSomething() { return true; }
}
The method exists on both types. When you use reflection and get the members of type Bar, you will actually find 2 methods called DoSomething() that look exactly the same. By using new you effectively hide the implementation in the base class, so that when classes derive from Bar (in my example) the method call to base.DoSomething() goes to Bar and not Foo.
Beyond just the technical details, I think using virtual/override communicates a lot of semantic information on the design. When you declare a method virtual, you indicate that you expect that implementing classes may want to provide their own, non-default implementations. Omitting this in a base class, likewise, declares the expectation that the default method ought to suffice for all implementing classes. Similarly, one can use abstract declarations to force implementing classes to provide their own implementation. Again, I think this communicates a lot about how the programmer expects the code to be used. If I were writing both the base and implementing classes and found myself using new I'd seriously rethink the decision not to make the method virtual in the parent and declare my intent specifically.
virtual / override tells the compiler that the two methods are related and that in some circumstances when you would think you are calling the first (virtual) method it's actually correct to call the second (overridden) method instead. This is the foundation of polymorphism.
(new SubClass() as BaseClass).VirtualFoo()
Will call the SubClass's overriden VirtualFoo() method.
new tells the compiler that you are adding a method to a derived class with the same name as a method in the base class, but they have no relationship to each other.
(new SubClass() as BaseClass).NewBar()
Will call the BaseClass's NewBar() method, whereas:
(new SubClass()).NewBar()
Will call the SubClass's NewBar() method.
The difference between the override keyword and new keyword is that the former does method overriding and the later does method hiding.
Check out the folllowing links for more information...
MSDN and Other
new keyword is for Hiding. - means you are hiding your method at runtime. Output will be based base class method.
override for overriding. - means you are invoking your derived class method with the reference of base class. Output will be based on derived class method.
My version of explanation comes from using properties to help understand the differences.
override is simple enough, right ? The underlying type overrides the parent's.
new is perhaps the misleading (for me it was). With properties it's easier to understand:
public class Foo
{
public bool GetSomething => false;
}
public class Bar : Foo
{
public new bool GetSomething => true;
}
public static void Main(string[] args)
{
Foo foo = new Bar();
Console.WriteLine(foo.GetSomething);
Bar bar = new Bar();
Console.WriteLine(bar.GetSomething);
}
Using a debugger you can notice that Foo foo has 2 GetSomething properties, as it actually has 2 versions of the property, Foo's and Bar's, and to know which one to use, c# "picks" the property for the current type.
If you wanted to use the Bar's version, you would have used override or use Foo foo instead.
Bar bar has only 1, as it wants completely new behavior for GetSomething.
Not marking a method with anything means: Bind this method using the object's compile type, not runtime type (static binding).
Marking a method with virtual means: Bind this method using the object's runtime type, not compile time type (dynamic binding).
Marking a base class virtual method with override in derived class means: This is the method to be bound using the object's runtime type (dynamic binding).
Marking a base class virtual method with new in derived class means: This is a new method, that has no relation to the one with the same name in the base class and it should be bound using object's compile time type (static binding).
Not marking a base class virtual method in the derived class means: This method is marked as new (static binding).
Marking a method abstract means: This method is virtual, but I will not declare a body for it and its class is also abstract (dynamic binding).
using System;
using System.Text;
namespace OverrideAndNew
{
class Program
{
static void Main(string[] args)
{
BaseClass bc = new BaseClass();
DerivedClass dc = new DerivedClass();
BaseClass bcdc = new DerivedClass();
// The following two calls do what you would expect. They call
// the methods that are defined in BaseClass.
bc.Method1();
bc.Method2();
// Output:
// Base - Method1
// Base - Method2
// The following two calls do what you would expect. They call
// the methods that are defined in DerivedClass.
dc.Method1();
dc.Method2();
// Output:
// Derived - Method1
// Derived - Method2
// The following two calls produce different results, depending
// on whether override (Method1) or new (Method2) is used.
bcdc.Method1();
bcdc.Method2();
// Output:
// Derived - Method1
// Base - Method2
}
}
class BaseClass
{
public virtual void Method1()
{
Console.WriteLine("Base - Method1");
}
public virtual void Method2()
{
Console.WriteLine("Base - Method2");
}
}
class DerivedClass : BaseClass
{
public override void Method1()
{
Console.WriteLine("Derived - Method1");
}
public new void Method2()
{
Console.WriteLine("Derived - Method2");
}
}
}

Getting methods from base class?

I am brand new to base classes so please correct me if I am wrong or I should be doing this another way, but I have coded a simple code snippet below that explains what I want to do.
class A : B
{
private int _classId;
public A (int id) : base(id)
{
_classId = id;
}
public string GetString()
{
return "This will eventually be an important string.";
}
}
class B
{
private int _classId;
public B (int id)
{
// here I want to be able to get access to class A's methods
// such as GetString() ...
}
public void SomeMethod()
{
}
}
So what I want to do is allow B to get A's methods.
Reason for doing this?
I don't want to populate the class A because B is going to have a lot of methods so it would be cleaner to keep them in B then just get them from A in other code. Am I doing this wrong? is this not what base classes do? I simply just want to be able to still do this:
A.SomeMethodInB();
Without populating class A with junk and making it cleaner by storing it in class B
Let me summarize your question:
You want a method that is only implemented in a descendant class (A)
You want this method to be available to both the base class (B) and the descendant class (A)
You want the base class to be able to call the descendant class' implementation of the method
This is the original definition of polymorphism (lately people have been using the term much more generally) and is bread-and-butter when it comes to OOP. It is also the hardest area of OOP to grasp for newcomers.
Write a base class with a virtual method
Let us start with the base class. Notice I have changed your example slightly, for a reason I will explain in a moment.
class B
{
virtual protected string GetString()
{
return "I am a B";
}
public void DoSomethingWithGetString()
{
Console.WriteLine(GetString());
}
}
In this example, DoSomethingWithGetString calls GetString. Note that GetString is virtual. This tells the compiler that we don't want to decide where the implementation of GetString is until runtime. This means it can't be bound at compile time: instead, its location is identified by a runtime Virtual Method Table that is set up when the object is created. If this code is running as part of a instance of class B, then it will call class B's implementation of GetString. But if this code was inherited, and is actually being called by some other object that descends from class B, it will call that class' version of GetString. This is called late binding.
Write the descendant class
So now let's write class A:
class A : B
{
protected override GetString()
{
return "I am an A.";
}
}
Because A descends from B, we don't need to implement anything else. If we call A.DoSomethingWithGetString it'll actually call B's implementation because it is inherited.
Execute it
If you run this code
var a = new A();
a.DoSomethingWithGetString(); //Output = "I am an A"
...the following will happen:
An instance of A, which descends from B, is created
The VMT of A is configured so that calls to GetString are sent to A.GetString.
You call A.DoSomethingWithGetString
This call is directed to B's code base, because A doesn't implement it.
The code base in B detects that GetString is a virtual method, and calls it using the VMT.
The VMT points to A's implementation of GetString.
A.GetString is executed.
Thus you have an situation where code in class B is calling code in class A, which is what you asked for.
You can also run it this way:
B b = new A();
b.DoSomethingWithGetString(); //Output = "I am an A"
Thus you have a pointer to a B that says it's an A, because it is using a VMT set up for class A.
But I don't want any implementation in class B
Now, let's say you don't want class B to have any implementation at all for GetString, but you still want to be able to call the implementation in A. There is a way to do this using an abstract virtual method. Simply add the abstract keyword and remove the implementation:
abstract class B
{
abstract protected string GetString(); //Notice no implementation
public void DoSomethingWithGetString()
{
Console.WriteLine(GetString());
}
}
Of course, now you can't use class B by itself, because it requires an implementation of GetString that will only be present in a descendant class. So you can no longer create an instance of B directly; you have to subtype, and use the subtype.
Can't use constructor
Now, you'll notice in my example I removed your constructor calls. There is a reason for this. A constructor should not ever call a method that is defined on a descendant class. The reason: during construction, constructors are called up and down the inheritance hierarchy, starting with the base class and moving down the descendant chain. That means, when you call B's constructor, A's constructor has not been called yet. if A's constructor hasn't run yet, we can't be sure that A has been properly set up yet, and therefore it is a really bad idea to call any of its methods.
There are some workarounds for this, but that is a topic for a different question.
If the method is only defined in Class A, then there is no way to access it through Class B.
If the method exists in both Class A and Class B, then you can use virtual method and override.
Think it is better to use the names BaseClass and DerivedClass in an example. The names A and B are kind of arbitrary. Although A comes before B, the names don't imply the direction of inheritance intended.
class Program
{
static void Main(string[] args)
{
var bc = new BaseClass(3);
var dc = new DerivedClass(5);
Console.WriteLine("Base Class Method A: " + bc.MethodA());
Console.WriteLine("Derived Class Method A: " + dc.MethodA());
Console.WriteLine("Base Class Method B: " + bc.MethodB());
Console.WriteLine("Derived Class Method B: " + dc.MethodB());
Console.ReadLine();
}
}
public class BaseClass {
protected int _classId;
public BaseClass(int classId) {
_classId = classId;
}
public virtual string MethodA() {
return "Method A in base class: " + _classId.ToString();
}
public string MethodB()
{
return "I am a method B in the base class: " + _classId.ToString();
}
}
public class DerivedClass : BaseClass {
public DerivedClass(int classId)
: base(classId)
{
}
public override string MethodA() {
return "Method A in derived class: " + _classId.ToString();
}
}
There are two ways you can go about this. Let me first set out an example.
Here we have the base class that contains a method:
public class Base
{
public void BaseMethod()
{
// Some method.
}
}
Here is the derived class, where we want to call the method:
public class DerivedClass : BaseClass
{
// We want to use BaseMethod() here.
}
In order to call a method from the base class, we use the base keyword.
public class DerivedClass : BaseClass
{
base.BaseMethod();
}
This is fine if you want to just call the base method. However, if we want to change the method and define it with a different function, we have to declare it as virtual in the base class, as so:
public class Base
{
public virtual void BaseMethod()
{
// Some method.
}
}
In the derived class, we can now use the keyword override to override the virtual method of the base class, which redefines it to do something else:
public class DerivedClass : BaseClass
{
public override void BaseMethod()
{
// Some new function.
}
}

Overridden virtual method in C#

In "The C# Programming Language" book Eric Lippert mentioned this:
A subtle point here is that an overridden virtual method is still considered to be a method of the class that introduced it, and not a method of the class that overrides it.
What is the significance of this statement? Why does it matter if the overridden virtual method is considered to be a method of the class that introduced it (or otherwise) since the overridden method will never be called unless you are dealing with the derived class?
It matters when you have a reference of one type pointing to an object of a different type.
Example:
public class BaseClass {
public virtual int SomeVirtualMethod() { return 1; }
}
public class DerivedClass : BaseClass {
public override int SomeVirtualMethod() { return 2; }
}
BaseClass ref = new DerivedClass();
int test = ref.SomeVirtualMethod(); // will be 2
Because the virtual method is a member of the base class, you can call the overriding method with a reference of the base class type. If it wasn't, you would need a reference of the derived type to call the overriding method.
When you are shadowing a method instead of overriding it, the shadowing method is a member of the derived class. Depending on the type of the reference you will be calling the original method or the shadowing method:
public class BaseClass {
public int SomeMethod() { return 1; }
}
public class DerivedClass : BaseClass {
public new int SomeMethod() { return 2; }
}
BaseClass ref = new DerivedClass();
int test = ref.SomeMethod(); // will be 1
DerivedClass ref2 = ref;
int test2 = ref2.SomeMethod(); // will be 2
Here's the full quote from the book:
A subtle point here is that an overridden virtual method is still considered to be a method of the class that introduced it, and not a method of the class that overrides it. The overload resolution rules in some cases prefer members of more derived types to those in base types; overriding a method does not "move" where that method belongs in this hierarchy.
At the very beginning of this section, we noted that C# was designed with versioning in mind. This is one of those features that helps prevent "brittle base-class syndrome" from causing versioning problems.
The full quote makes it clear that Eric Lippert is talking specifically about method overloading, not just about how virtual methods work.
As an example, consider the following program:
class Base
{
public virtual void M2(int i) { }
}
class Derived : Base
{
public void M1(int i) { Console.WriteLine("Derived.M1(int)"); }
public void M1(float f) { Console.WriteLine("Derived.M1(float)"); }
public override void M2(int i) { Console.WriteLine("Derived.M2(int)"); }
public void M2(float f) { Console.WriteLine("Derived.M2(float)"); }
public static void Main()
{
Derived d = new Derived();
d.M1(1);
d.M2(1);
}
}
I think many developers would be surprised that the output is
Derived.M1(int)
Derived.M2(float)
Why would d.M2(1) invoke Derived.M2(float) even though Derived.M2(int) is a better match?
When the compiler is determining what the M1 in d.M1(1) refers to, the compiler sees that both M1(int) and M1(float) are introduced in Derived, so both overloads are applicable candidates. The compiler selects M1(int) over M1(float) as the best match for the integer argument 1.
When the compiler is determining what the M2 in d.M2(1) refers to, the compiler sees that M2(float) is introduced in Derived and is an applicable candidate. According to the overload resolution rules, "methods in a base class are not candidates if any method in a derived class is applicable". Because M2(float) is applicable, this rule prevents M2(int) from being a candidate. Even though M2(int) is a better match for the integer argument and even though it's overridden in Derived, it's still considered to be a method of Base.
Understanding that an overridden virtual method belongs to the class which introduces it, rather than the class that overrides it, makes it easier to understand the way class members are bound. Except when using dynamic objects, all bindings in C# are resolved at compile time. If a BaseClass declares a virtual method foo, and DerivedClass:BaseClass overrides foo, code which attempts to call foo on a variable of type BaseClass will always be bound to virtual method "slot" BaseClass.foo, which will in turn point to the actual DerivedClass.foo method.
This understanding can be especially important when dealing with generics, since in C#, unlike C++, members of generic types are bound according to the generics' constraints, rather than according to the concrete generic types. For example, suppose there were a SubDerivedClass:DerivedClass which created a new virtual method foo(), and one defined a method DoFoo<T>(T param) where T:BaseClass {param.foo();}. The param.foo() call would be bound to BaseClass.foo even if the method were invoked as DoFoo<SubDrivedClass>(subDerivedInstance). If the parameter were cast to SubDerivedClass before invoking foo, the call would be bound to SubDrivedClass.foo(), but the compiler can't tell when producing DoFoo<T> that T will be anything more specific than BaseClass, it can't bind to anything that doesn't exist in BaseClass.
Incidentally, there are times it would be useful if a class could simultaneously override a base-class member and create a new one; for example, given an abstract base class ReadableFoo with some abstract read-only property, it would be helpful if a class MutableFoo could both provide an override for that property and define a read-write property with the same name. Unfortunately, .net does not allow that. Given such a restriction, the best approach may be for ReadableFoo to provide a concrete non-virtual read-only property which calls an protected abstract method with a different name to get the value. That way, a derived class could shadow the read-only property with a read-write one (that would call the same virtual method for reading, or a new (possibly virtual) method for writing.
(following is untested)
class BaseClass
{
public virtual void foo() {Console.WriteLine("BaseClass.Foo");
}
class DerivedClass:BaseClass
{
public override void foo() {Console.WriteLine("Derived.Foo");
}
class SubDerivedClass:DerivedClass
{
public new virtual void foo() {Console.WriteLine("SubDerived.Foo");
}
class MegaDerivedClass:SubDerivedClass
{
public override void foo() {Console.WriteLine("MegaDerived.Foo");
}
void DoFoo1<T>(T param) where T:BaseClass
{
param.foo();
}
void DoFoo1<T>(T param) where T:SubDerivedClass
{
param.foo();
}
void test(void)
{
var megaDerivedInstance = new MegaDerivedClass();
DoFoo1<MegaDerivedClass>(megaDerivedInstance);
DoFoo2<MegaDerivedClass>(megaDerivedInstance);
}
A SubDerivedClass has two virtual foo() methods: BaseClass.foo() and SubDerivedClass.foo(). A MegaDerivedClass has those same two methods. Note that classes derived from SubDerivedClass() which attempt to override foo will override SubDerivedClass.foo() and will not affect BaseClass.foo(); with the declarations as above, no derivative of SubDerivedClass can override BaseClass.Foo. Note also that casting an instance of SubDerivedClass or a subclass thereof to DerivedClass or BaseClass will expose the BaseClass.foo virtual method for calling.
Incidentally, if the method declaration in SubDerivedClass had been friend new virtual void foo() {Console.WriteLine("SubDerived.Foo");, it would be impossible for other classes within the same assembly to override BaseClass.foo() (since any attempt to override foo() would override SubDerivedClass.foo()), but classes outside the assembly which derive from SubDerivedClass wouldn't see SubDerivedClass.foo() and could thus override BaseClass.foo().

When creating a derived class in C#, is it possible to overwrite a 0 parameter virtual function with an n parameter function?

I checked out MSDN and a couple other sites but I'm still not sure I got an answer for this. If you have a Parent class with a virtual function Init(), can I then--in the derived class--have an override function Init(int num) or do you simply have to create a new function for each derived class you make? If I'm not mistake, the latter would cause you to have 2 Init functions in the Child class, right? Here's sort of what I mean:
public class Parent {
protected int a;
public Parent() {
a=1;
}
public virtual void Init() {
}
}
public class Child : Parent {
public Child() {
}
//is this allowed?
public override void Init(int multiplier) {
}
//or do i have to do this and have 2 Init functions?
public void Init(int multiplier) {
}
}
You're not actually overriding the method, you're simply defining a new overload.
To be able to override a method, the base method must be declared a public (or protected) virtual (or abstract) method and your derived class must use the same exact signature.
In your case, no overridable method with that signature exists in the base class so it is not allowed. It would be allowed if an overridable method existed with the signature Init(int) but there isn't, the compiler would yield an error here.
This is not possible.
What would the parameter be if it's called from the base class?
An override needs to have the same signature, otherwise there is no point in making it virtual.
//is this allowed?
public override void Init(int multiplier) {
}
This is not an override.
Since you are introducing new multiplier it would be considered new method.
However if you do this.
public override void Init(){}
It will be override.
However if you do this in derived class it will be considered overload.
public void Init(int Multiplier)
{}
The compiler will give you an error, because "there is nothing to override".
Basically, the overridden method must match the underlying signature:
http://msdn.microsoft.com/en-us/library/ms173153.aspx

c# generic method overload not consistent with abstract Visitor pattern

experimenting with Visitor pattern and generic method I found a kind of discrepancy in C#.NET. AFAIK C# compiler prefers an explicit overload to a generic method, therefore the following code:
public abstract class A
{
public abstract void Accept(Visitor v);
}
public class B : A
{
public override void Accept(Visitor v)
{ v.Visit(this); }
}
public class C : A
{
public override void Accept(Visitor v)
{ v.Visit(this); }
}
public class D : A
{
public override void Accept(Visitor v)
{ v.Visit(this); }
}
public class Visitor
{
public void Visit(B b)
{ Console.WriteLine("visiting B"); }
public void Visit(C c)
{ Console.WriteLine("visiting C"); }
public void Visit<T>(T t)
{ Console.WriteLine("visiting generic type: " + typeof(T).Name); }
}
class Program
{
static void Main()
{
A b = new B();
A c = new C();
A d = new D();
Visitor v = new Visitor();
b.Accept(v);
c.Accept(v);
d.Accept(v);
}
}
The output produced is (as expected):
visiting B
visiting C
visiting generic type: D
However this Visitor pattern implementation does not allow to exchange the Visitor class. Introducing an abstract class VisitorBase and forwarding the call to the overloads produces smth. unexpected for me....
public abstract class A
{
public abstract void Accept(VisitorBase v);
}
public class B : A
{
public override void Accept(VisitorBase v)
{ v.Visit(this); }
}
public class C : A
{
public override void Accept(VisitorBase v)
{ v.Visit(this); }
}
public class D : A
{
public override void Accept(VisitorBase v)
{ v.Visit(this); }
}
public abstract class VisitorBase
{
public abstract void Visit<T>(T t);
}
public class Visitor : VisitorBase
{
protected void VisitImpl(B b)
{ Console.WriteLine("visiting B"); }
protected void VisitImpl(C c)
{ Console.WriteLine("visiting C"); }
protected void VisitImpl<T>(T t)
{ Console.WriteLine("visiting generic type: " + typeof(T).Name); }
public override void Visit<T>(T t)
{
VisitImpl(t); //forward the call to VisitorImpl<T> or its overloads
}
}
class Program
{
static void Main()
{
A b = new B();
A c = new C();
A d = new D();
VisitorBase v = new Visitor();
b.Accept(v);
c.Accept(v);
d.Accept(v);
}
}
Now the output is:
visiting generic type: B
visiting generic type: C
visiting generic type: D
Do generic methods only prefer generic methods? Why are no explicit overloads called?
Overloading is done statically, so when you call VisitImpl(t), the compiler must pick the single best overloaded method that this call represents (if there is one). Since the type parameter T could be anything, the only method which is compatible is the generic method, and therefore all calls from Visit<T>(T t) call into VisitImpl<T>(T t).
EDIT
It looks like you may be coming from a C++ background, so perhaps it's worth noting that C++ templates are very different from C# generics; in particular, there's no such thing as specialization in C#, which may be why the behavior you see is unexpected. The C# compiler does not emit different code for the different types at which a generic method may be called (that is, the C# compiler calls the same generic method when you call Visit(1) and Visit("hello"), it does not generate specializations of the method at types int and string). At runtime, the CLR creates type specific methods, but this happens after compilation and cannot affect overload resolution.
EDIT - even more elaboration
C# does prefer non-generic methods to generic methods when the non-generic method is statically known to be applicable.
The C# compiler will pick a single method to call at any given call-site. Forget about overloading entirely, and give your methods each a different name; which of those renamed methods can be called at the call-site in question? Only the generic one. Therefore, even when the three names collide and overload resolution kicks in, that is the only overload which is applicable at that site, and is the method chosen.
As I understand it, and I could be very wrong, at compile time the generic function visit actually performs a sort of unboxing of the original type. While we can logically see that the types should run through at compile time, the C# compiler can't make it through the Visit function to the VisitImpl function while holding the types, so the original b.visit(v) is considered unboxed at compile. Given this, it must route through the generic for all types that match when the Visit method is called.
EDIT: To clarify what I mean because I just read my own crap:
The compiler holds the link for b.Visit as a generic call. It fits and is labeled generic.
The compiler holds separate links for Visit->VisitImpl as typed and/or generic methods as necessary.
The compiler can not hold a link from b.Visit (as generic) -> VisitImpl as typed. Since the path from b.Visit() -> VisitImpl must go through a generic, it holds it as a generic type and so the generic VisitImpl is preferred.
It seems you're confusing overloading and overriding.
Overloading is when you provide multiple methods with the same name, that differ in parameter types:
class Foo
|
+- void Qux(A arg)
+- void Qux(B arg)
+- void Qux(C arg)
Overriding is when you provide multiple implementations of the same (virtual) method:
class Foo class Bar : Foo class Baz : Foo
| | |
+- virtual void Quux() +- override void Quux() +- override void Quux()
C# performs single dispatch:
The overload of an invoked method is determined at compile-time.
The implementation of an overridden method is determined at run-time.
The visitor pattern exploits the latter by dispatching the method call to the right implementation of the Visit method. In languages with multiple dispatch, the visitor pattern is not needed because the right overload is chosen at run-time.
Generics are a compiler feature, so only information available at compile time is used to determine what method should be called. What you are doing would require at runtime to determine what the actual type of the variable is. The compiler only knows that variable b is of type A, c is of type A, and d is of type A. It's picking the best overload, which is the generic one, as there is no method that takes A.

Categories

Resources