Why this difference of handling method ambiguity in Java & c#? [duplicate] - c#

This question already has answers here:
Why does Java and C# differ in oops?
(2 answers)
Closed 9 years ago.
I have two classes A & B, where B is derived from A.
Both the classes have a method with same signature. They are called in the following manner in Java & c#-->
In case of JAVA :
class A
{
public void print()
{
System.out.println("Inside Parent");
}
}
class B extends A
{
public void print()
{
System.out.println("Inside Child");
}
}
class test4
{
public static void main(String args[])
{
B b1=new B();
b1.print();
A a1=new B();
a1.print();
}
}
This program generates the following output:-
Inside Child
Inside Child
In case of C# :
class A
{
public void print()
{
System.Console.WriteLine("Inside Parent");
}
}
class B : A
{
public void print()
{
System.Console.WriteLine("Inside Child");
}
}
class Program
{
public static void Main(string[] args)
{
B b1=new B();
b1.print();
A a1=new B();
a1.print();
System.Console.Read();
}
}
This program generates the following output:-
Inside Child
Inside Parent
Why does the output differ ?

In Java, methods are virtual by default.
In C#, methods are not virtual by default.
So, in order for the C# code to behave the same as the Java code, make the method virtual in the base class and override in the derived class.
Or, in order for the Java code to behave the same as the C# code, make the method final in the base class.

In case of c# you need to make the parent method as virtual and child method as an override
class A
{
public virtual void print()
{
System.Console.WriteLine("Inside Parent");
}
}
class B : A
{
public override void print()
{
System.Console.WriteLine("Inside Child");
}
}
class Program
{
public static void Main(string[] args)
{
B b1=new B();
b1.print();
A a1=new B();
a1.print();
System.Console.Read();
}
}

This line:
A a1=new B();
I think here, in C# you have an example of method hiding. Perhaps you need to explicitly declare the method as overridden (for example in java using the #Override annotation).

Related

Out-line for virtual method in C# [duplicate]

This question already has answers here:
Why does this polymorphic C# code print what it does?
(5 answers)
Closed 6 years ago.
I have an example of code in C#
using System;
class A
{
public virtual void F() { Console.WriteLine("A.F"); }
}
class B: A
{
public override void F() { Console.WriteLine("B.F"); }
}
class C: B
{
new public virtual void F() { Console.WriteLine("C.F"); }
}
class D: C
{
public override void F() { Console.WriteLine("D.F"); }
}
class Test
{
static void Main() {
D d = new D();
A a = d;
B b = d;
C c = d;
a.F();
b.F();
c.F();
d.F();
}
}
This code outline
B.F
B.F
D.F
D.F
I do not understand why in case a.F();
There is B.F ?
how MS said the virtual methods is represended by type of object in real time
I do not understand why in case a.F(); There is B.F ?
MSDN #
When a virtual method is invoked, the run-time type of the object is
checked for an overriding member. The overriding member in the most
derived class is called, which might be the original member, if no
derived class has overridden the member.
Bold content will explain to you why B.F is printed when A.F() is called.
The call to method F() from your inherited class object prints B.F for the object of type D downcasted to type A, because you override the method in class B (and class D).
Your test is an almost exact copy of the example provided in this MSDN post on virtual methods:
using System;
class A
{
public void F() { Console.WriteLine("A.F"); }
public virtual void G() { Console.WriteLine("A.G"); }
}
class B: A
{
new public void F() { Console.WriteLine("B.F"); }
public override void G() { Console.WriteLine("B.G"); }
}
class Test
{
static void Main() {
B b = new B();
A a = b;
a.F();
b.F();
a.G();
b.G();
}
}
In the example, A introduces a non-virtual method F and a virtual
method G. The class B introduces a new non-virtual method F, thus
hiding the inherited F, and also overrides the inherited method G. The
example produces the output:
A.F
B.F
B.G
B.G
Notice that the statement
a.G() invokes B.G, not A.G. This is because the run-time type of the
instance (which is B), not the compile-time type of the instance
(which is A), determines the actual method implementation to invoke.
Because methods are allowed to hide inherited methods, it is possible
for a class to contain several virtual methods with the same
signature. This does not present an ambiguity problem, since all but
the most derived method are hidden. In the example
In case of a.F() there is B.F because virtual void F in class A is override in B.
It is not override by C, because there is a new operator which does not override the virtual base method.
So if there is an instance of type D typed to A and you call F(), virtual method from the class A is called, but the latest override is taken into account. That is B.F.

Exposing only some inherited methods in the derived class

I stumbled across an interview question related to OOPS. Here is the question:
There is a base class A with 5 methods. Now how should I design the class such that if a class B inherits class A, only 3 methods are exposed. And if a class C inherits class A, the rest of the 2 methods are exposed.
Any thoughts ??
if A is partial and you have 2 namespaces then:
namespace the_impossible
{
class Program
{
static void Main(string[] args)
{
B b = new B();
C c = new C();
b.m1();
b.m2();
b.m3();
c.m4();
c.m5();
}
}
namespace A_1
{
public partial class A
{
public void m1() { }
public void m2() { }
public void m3() { }
}
}
namespace A_2
{
public partial class A
{
public void m4() { }
public void m5() { }
}
}
class B : A_1.A
{
}
class C : A_2.A
{
}
}
It should not be possible in any object-oriented language, otherwise it would break the Liskov substitution principle. Substituting a B for an A should not reduce its correctness (meaning methods should not suddenly be unavailable)
However, there is still some ambiguity in the question that allows for some "out-of-the-box" thinking. Here are questions I would pose back to the interviewer:
What do you mean by "exposed"?
Do the 5 methods in A have to be public?
Does the "exposition" by C need to be implicit or can the be explicitly exposed (e.g. pass-through)
Based on those answers you could either come up with possible options using internal, explicit interface implementations, etc.
I think it was a trick or even dumb question. To achieve this, we must break the Liskov substitution principle. You shouldn't preseve the hierarchy of the classes.
Maybe you just should use interfaces instead:
public class A {} //why we even need this class?
public class B : A, I3Methods
{
public void Method1() { }
public void Method2() { }
public void Method3() { }
}
public class C : A, I2Methods
{
public void Method4() { }
public void Method5() { }
}
public interface I3Methods
{
void Method1();
void Method2();
void Method3();
}
public interface I2Methods
{
void Method4();
void Method5();
}
The only way I can think of is to have them all private in A and then expose them through encapsulation in B and C... But they are not exposed, only executed... So it is half right.
I also think that's impossible.
But to give an approximate answer:
Make 3 methods in A virtual, then implement them in B. Then override those 2 methods in C.
Nobody says that the 5 methods of class A should be exposed when writing them. In C# you could simply write 5 protected methods in class A and expose those you wish to be accessible by writing some hiding methods with the new modifier like this - although this wouldn't actually expose the methods directly they are merely wrapped.
class A
{
protected void M1() { }
protected void M2() { }
protected void M3() { }
protected void M4() { }
protected void M5() { }
}
class B : A
{
public new void M1()
{
base.M1();
}
public new void M2()
{
base.M2();
}
public new void M3()
{
base.M3();
}
}
class C : A
{
public new void M4()
{
base.M4();
}
public new void M5()
{
base.M5();
}
}
In your comments, you mentioned that you were interested if this could be done in any other language. You can kind of do it in C++ through the use of the using keyword. So, starting with class A:
class A {
public:
int Method1() { return 1; }
int Method2() { return 2; }
int Method3() { return 3; }
int Method4() { return 4; }
int Method5() { return 5; }
};
Then you define class B, using private inheritance (essentially you can't auto cast from B to A and all public methods in A become private methods in B).
class B: private A {
public:
// We want to expose methods 1,2,3 as public so change their accessibility
// with the using keyword
using A::Method1;
using A::Method2;
using A::Method3;
};
Do the same for class C, exposing the other two methods instead:
class C: private A {
public:
using A::Method4;
using A::Method5;
};
Or if you're supposed to expose all the methods through C, simply use public inheritance and everything exists:
class C: public A {
public:
};
For usage:
B *b = new B();
b->Method1(); // This works, Method1 is public
b->Method4(); // This fails to compile, Method4 is inaccessible
The reason I said kind of above is because you can work around it by explicitly casting the instance of B to an A:
A *brokena = b; // This wouldn't compile because the typecast is inaccessible
A *a = (A*)b; // This however does work because you're explicitly casting
a->Method4(); // And now you can call Method4 on b...
I know, it is to late to respond. Just thought of sharing my thoughts:
Define Class A as a base class.
Have intermediate child classes A1 -> M1,M2,M3 and A2 -> M4, M5 deriving from Class A
Now, you can have
1) Class B inheriting A1
2) Class C inheriting A2
These two classes are still derived from Class A.
And also we are not breaking liskov substitution principle.
Hope, this gives clarity.

Dynamic type and static type C#

I'm experimenting with C# and I built the following program (see below).
I understand that the dynamic and static type of first is C. For second the dynamic type is also C but the static type is A. Now I wonder where this might come in handy?
I noticed as well (obviously) that visual studio doesn't allow me to call second.CallA().
Now notice that when I call DoA() on all three types of static type, the dynamic type is C. As this is the case, why doesn't this point to that class? If i recall correct (I might be mistaking) in Java a self.methodA() would start looking up the inhertence tree from the caller instance. As it doesn't appear to be like that here. Can I create such behavior or is this a limitation of the language?
public class A
{
public void methodA()
{
Console.WriteLine("I am class A!");
}
public void DoA()
{
Console.Write("The type of this: " + this.GetType() + " - ");
this.methodA();
}
}
public class B : A
{
public void methodA()
{
Console.WriteLine("I am class B!");
}
}
public class C : B
{
public void methodA()
{
Console.WriteLine("I am class C!");
}
}
class Program
{
static void Main(string[] args)
{
C first = new C();
A second = new C();
dynamic third = new C();
//Show the types of both
Console.WriteLine(first.GetType() + "\n" + second.GetType() + "\n" + third.GetType());
first.methodA();
second.methodA();
third.methodA();
first.DoA();
second.DoA();
third.DoA();
Console.ReadLine();
}
Output:
C
C
C
I am class C!
I am class A!
I am class C!
The type of this: C - I am class A!
The type of this: C - I am class A!
The type of this: C - I am class A!
Can I create such behavior or is this a limitation of the language?
You can create such behavior. In order to do so, you need to make your methods virtual. This will give you that behavior, without using dynamic at all.
public class A
{
public virtual void methodA()
{
Console.WriteLine("I am class A!");
}
Then, later:
public class B : A
{
public override void methodA()
{
Console.WriteLine("I am class B!");
}
}
In C#, you must explicitly make your methods virtual. In Java, methods are effectively virtual by default. This isn't a limitation of the language - it's just a difference between the two languages.

How to achieve same override experience in C# as in Java?

Considering the following Java code:
public class overriding {
public static void main(String[] args) {
b b = new b();
a a = (a)b;
a.Info();
b.Info();
}
}
class a {
void Info() {
System.out.println("I'm a");
}
}
class b extends a {
void Info() {
System.out.println("I'm b");
}
}
And now let's try to do the same in C#
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
b b = new b();
a a = (a)b;
a.Info();
b.Info();
Console.ReadLine();
}
}
class a
{
public void Info()
{
Console.WriteLine("I'm a");
}
}
class b : a
{
public void Info()
{
Console.WriteLine("I'm b");
}
}
}
The Java example output
I'm b
I'm b
The C# version output
I'm a
I'm b
Is there a way to implement class b so that it prints "I'm b" twice? Please notice i'm not looking at a way to change a.
In Java, methods are virtual by default. In C# they are not, and you need to use the keywords "virtual" and "override" for the method declarations in classes a and b, respectively.
In C# version, you need to use override keyword in the class b method, and also you need to make the method in class a virtual explicitly. In Java, methods are virtual by default. That's not the case in C#. You need to tell that explicitly:
class a
{
public virtual void Info()
{
Console.WriteLine("I'm a");
}
}
class b : a
{
public override void Info()
{
Console.WriteLine("I'm b");
}
}
No. By design. c# has virtual methods that you may override in subclasses. The idea is, that the possibility for override is part of the classes contract.
In the Java model, a subclass might break behavior by naming a new method the same as a base method but not providing the proper behavior.
In c# you need to be explicit about this.
One major difference between Java and C# is that in Java, methods are virtual by default. To do the same in C#, you need to mark the method a.Info as virtual and then use the override keyword in b:
class a
{
public virtual void Info()
{
Console.WriteLine("I'm a");
}
}
class b : a
{
public override void Info()
{
Console.WriteLine("I'm b");
}
}
UPDATE
You can also use the new keyword on class b without needing the virtual keyword on a:
class a
{
public void Info()
{
Console.WriteLine("I'm a");
}
}
class b : a
{
public new void Info()
{
Console.WriteLine("I'm b");
}
}
However, this will only produce "I'm b" when the object is of type b, but will say "I'm a" when it is cast back to b:
b myB= new b();
myB.Info(); // This will say "I'm b"
a myA = (a)myB;
myA.Info(); // This will say "I'm a" even though it's really a b object.
See MSDN more info
In Java , we are not using any keywords for method overloading and method overriding. While in C#, you have to use override for method overriding explicitly.
public override void Info()
{
Console.WriteLine("I'm b");
}

Call of overloaded method from generic method issue

I've run into interesting thing (works same in both Java and C#).
Java code:
public class TestStuff {
public static void main(String[] args) {
Printer p = new PrinterImpl();
p.genericPrint(new B());
}
}
class PrinterImpl implements Printer {
void print(A a) {
System.out.println("a");
}
void print(B b) {
System.out.println("b");
}
#Override
public <T extends A> void genericPrint(T b) {
print(b);
}
}
interface Printer {
public <T extends A> void genericPrint(T a);
}
class A {
}
class B extends A{
}
C# code:
namespace TestStuff
{
internal class Program
{
private static void Main(string[] args)
{
var printer = new Printer();
printer.GenericPrint(new B());
}
}
public class Printer
{
public void Print(A a)
{
Console.WriteLine("a");
}
public void Print(B b)
{
Console.WriteLine("b");
}
public void GenericPrint<T>(T a) where T : A
{
Print(a);
}
}
public class B : A
{
}
public class A
{
}
}
When I wrote something like this I expected to see "b" printed in both cases.
But, as you can see, it is "a" what is printed.
I've read C# language specification and it says overloaded method is selected at compile-time. It explains why it works that way.
However, I had no time to check it out in Java language specification.
Could somebody please give a more detailed explanation of what is happening and why? And how could I achieve what I wanted?
Thanks in advance!
The key is to understand that generics are only available at compile time in java. It is just syntax sugar that the compiler uses while compiling, but throws away while generating the class files.
As such, the code:
public <T extends A> void genericPrint(T b) {
print(b);
}
is compiled into:
public void genericPrint(A b) {
print(b);
}
Since the argument to print is of type A, the overloaded version print(A a) is the one resolved. I'd suggest using polymorphic calls on instances of A or the Visitor pattern to callback into PrinterImpl for your use case.
Something like:
interface Visitor {
void visit(A a);
void visit(B b);
}
class PrinterImpl implements Printer, Visitor {
void print(A a) {
System.out.println("a");
}
void print(B b) {
System.out.println("b");
}
public <T extends A> void genericPrint(T b) {
b.accept(this);
}
public void visit(A a) {
print(a);
}
public void visit(B b) {
print(b);
}
}
interface Printer {
public <T extends A> void genericPrint(T a);
}
class A {
public void accept(Visitor v) {
v.visit(this);
}
}
class B extends A {
public void accept(Visitor v) {
v.visit(this);
}
}
Its true that overloaded methods are selected at compile time and its true for java also(dynamic method dispatch).
However Generics works a little differently. Your method GenericPrinter can only work Types A or its derivative. Its a constraint on that method. Suppose in your GenricPrinter class you have invoked a method thats defined in A.
public class A
{
void DoSomethingA()
{
}
}
.
.
.
public void GenericPrint<T>(T a) where T : A
{
//constraint makes sure this is always valid
a.DoSomethingA();
Print(a);
}
So this constraint would make sure that only A or its sub classes, that contains the above method would only be allowed.
Although you pass in an instance of A's subclass but due to constaint, GenericPrinter would treat the subclass as A.
Just remove the constraint part (T:A) and B would be printed as you expect.
There is no runtime check of which type a is in your GenericPrint method. The only thing you enforce with the where T : A part, is that you can call Print.
Btw, apart from that generic method: If you want a to be printed, although it is an instance of B, then you have to declare that variable as A obj = new B().

Categories

Resources