2

If I have a base class

class Foo : IClonable {

    public object virtual Clone(){ return new Foo(); }  
}

and a child class incorrectly overriding clone with new instead of override. It's a simplification of a bug in a third party library I'm trying to work around.

class Bar : Foo {

    public new Clone() { return new Bar(); }
}

and then I have two methods

public static T Bang(T source)
where T : Foo
{
    return (T) source.Clone();
}

and

public static Bar Bang(Bar source)
{
    return (Bar) source.Clone();
}

now if I invoke the first one with an instance of Bar I get a Foo back. If I invoke the second I get Bar back.

I'm curious as to why the generic version doesn't get the new version of Clone() but rather the inherited version.

Is it that the type T is erased after the constraints are met and then it just behaves using the base class?

Kara
  • 6,115
  • 16
  • 50
  • 57
bradgonesurfing
  • 30,949
  • 17
  • 114
  • 217
  • Take a look at this [question](http://stackoverflow.com/questions/10740981/c-sharp-generics-why-is-method-in-base-class-called-instead-of-new-method-in) maybe can help. – Alessandro D'Andria Mar 20 '14 at 15:34

2 Answers2

1

Is it that the type T is erased after the constraints are met and then it just behaves using the base class?

It depends on what you mean by "the type T is erased". It's not erased in the same way that it is in Java - the type argument is available at execution time, so if you write:

Console.WriteLine(typeof(T));

that will print Bar.

However, the compiler needs to determine which method to call when it compiles your first Bang method is that the value is of type Foo or some subtype. It has to generate IL calling one method based on that. It's not like the compiler generates a new Bang method for every different T, using the actual type T to perform method resolution etc.

In other words, as far as the compiler is concerned your method is equivalent to:

public static T Bang<T>(Foo source)
where T : Foo
{
    return (T) source.Clone();
}

Note the change of the parameter type from T to Foo, because that's all the information the compiler has to go on.

(I'm assuming that you understand that your two Clone methods are mostly unrelated as far as the compiler and CLR are concerned; they happen to have the same name, but one doesn't override the other polymorphically.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • The answer was what I expected I guess. Yes I do understand there was a difference. This was a bug in a third party closed source library. They should have used override instead of new but I was just curious at the way the compiler dealt with it. – bradgonesurfing Mar 21 '14 at 05:58
1

In short, new is not the same as override. new indicates shadowing of a method, meaning the derived implementation has changed but the base implementation remains the same. override will change the base implementation as well.

In shadowing, only the derived type's implementation is changed. This means that if the object is typed as the base type, it will use the base method. Your generic constraint types T to the base type of Foo.

var bar = new Bar();
var result = bar.Clone(); // returns Bar
var result2 = ((Foo)bar).Clone(); // returns Foo
Haney
  • 32,775
  • 8
  • 59
  • 68