Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this generic method call the base class method, not the derived class method?

Tags:

c#

generics

For the following code:

class B
{
    public String G() { return "B.G()"; }
}

class D : B
{
    public String G() { return "D.G()"; }
}

class TestCompile
{
    private static String TestG<T>(T b) where T: B 
    {
        return b.G();
    }

    static void Main(string[] args)
    {
        TestG(new D());
    }
}

The result is B.G(), whereas the result of similar C++ code would be D.G().

Why is there this difference?

like image 406
CPW Avatar asked Nov 29 '11 12:11

CPW


People also ask

How do you call a base class method from a derived class in C#?

base (C# Reference) The base keyword is used to access members of the base class from within a derived class: Call a method on the base class that has been overridden by another method. Specify which base-class constructor should be called when creating instances of the derived class.

Can a generic class be derived from another generic class?

In the same way, you can derive a generic class from another generic class that derived from a generic interface. You may be tempted to derive just any type of class from it. One of the features of generics is that you can create a class that must implement the functionality of a certain abstract class of your choice.

How to define a generic method in c#?

A method declared with the type parameters for its return type or parameters is called a generic method. Above, the AddorUpdate() and the GetData() methods are generic methods. The actual data type of the item parameter will be specified at the time of instantiating the DataStore<T> class, as shown below.


3 Answers

Use the override keyword:

class B
{
    public virtual String G() { return "B.G()"; }
}

class D : B
{
    public override String G() { return "D.G()"; }
}

Without the override keyword, the inherited method doesn't replace the base one.

Without override:

D obj = new D();
obj.G(); // "D.G()"
((B)obj).G(); // "B.G()"

With override:

D obj = new D();
obj.G(); // "D.G()"
((B)obj).G(); // "D.G()"
like image 197
Kevin Gosse Avatar answered Nov 03 '22 00:11

Kevin Gosse


C# generics are compiled only once: at the time the generic is compiled. (Think about it: C# lets you use List<T> without seeing its implementation.) Here, it sees from the where T: B clause that the parameter is a B, so it calls B.G.

C++ templates are compiled each time they are invoked. When you type TestG<D>(), a brand new copy of TestG is compiled with T = D. At invocation time, the compiler sees that D has its own G method and calls it.

The C++ equivalent of the C# generic would be

template<typename T>
string TestG(T t)
{
    B& b = static_cast<B&>(t); // force `t` into a `B`
    return b.G();
}

The remarks of others regarding the use of virtual apply equally to C# and C++. I'm just explaining why C++ behaves differently from C#.

like image 23
Raymond Chen Avatar answered Nov 02 '22 23:11

Raymond Chen


Becuase you've neglected to mark B.G as virtual, and D.G as override.

You got this compiler warning:

CS0108: 'D.G()' hides inherited member 'B.G()'. Use the new keyword if hiding was intended.

but you chose to ignore it. I would expect better from a C++ developer! :)

like image 36
AakashM Avatar answered Nov 02 '22 23:11

AakashM