0

Consider the following code :

class Program
{
    static void Main(string[] args)
    {
        var a = new A();
        var b = new B();
        Print(a);
        Print(b);
        Console.WriteLine(b.Hello);
        Console.ReadLine();
    }

    static void Print<T>(T t) where T : A
    {
        Console.WriteLine(typeof(T));
        Console.WriteLine(t.GetType());
        Console.WriteLine(t.Hello);
    }
}

public class A
{
    public string Hello { get { return "HelloA"; } }
}

public class B : A
{
    public new string Hello { get { return "HelloB"; } }
}

The output I got (.NET FW 4.5)

  • //Print(a)
  • A
  • A
  • HelloA
  • //Print(b)
  • B
  • B
  • HelloA
  • //Explicit Writeline
  • HelloB

Can anyone explain how I got the 2nd HelloA, as I was expecting HelloB ?

Benny
  • 207
  • 1
  • 7
  • 1
    you need to override the hello function. not to add a new one. – AMember Sep 12 '17 at 11:50
  • Because in `Print()` method, when you printing `Hello` for class `B`, in that point he has 2 `Hello`'s, one local, one from base class and `Console.WriteLine()` method will print out the base one, cause it hides the inherited class property with same name. – SᴇM Sep 12 '17 at 11:56
  • The concept you have implemented is called as shadowing and you are expecting the result that can be achieved after overriding. – Abhay Dixit Sep 12 '17 at 12:00

1 Answers1

5
public new string Hello { get { return "HelloB"; } }

The new keyword creates a new function which just happens to have the same name as the old one. Thus, B now has two methods: Hello (A), which is executed when invoked through a variable of compile-time type A, and Hello (B), which is executed when invoked through a variable of compile-time type B (or a subtype thereof).

Since your generic parameter is T : A, the compiler compiles t.Hello as a call to Hello (A).

B shadows (or hides) method Hello rather than overriding it.

What you probably wanted to write was:

public class A
{
    public virtual string Hello { get { return "HelloA"; } }
}

public class B : A
{
    public override string Hello { get { return "HelloB"; } }
}

Note that the base method is declared as virtual, and the subclass method as override.

Heinzi
  • 167,459
  • 57
  • 363
  • 519
  • Your answer is better than mine. +1. – Zohar Peled Sep 12 '17 at 11:55
  • "Since your generic parameter is T : A, the compiler compiles t.Hello as a call to Hello (A).", why is that ? I would have assumed that the method address will be decided in runtime, since T : A, we can't know in advance that this method is A.Hello – Benny Sep 12 '17 at 12:30
  • 2
    @Benny: Generics are *not* run-time method binding. You can only access methods whose presence can be verified at compile-time: You *need* `T : A` to be able to call `t.Hello`. You *cannot* call `t.SomeMethodOnlyDefinedOnB`, which is (essentially) what `Hello` (B) is. The fact that C# allows you to reuse the name is just syntactic sugar. You can think of shadowing as some compiler magic which allows you to write `Hello` where you would actually need to write `SomeMethodWithAnotherNameThanHello`. – Heinzi Sep 12 '17 at 12:52