39

In C# the new modifier can be used to hide a base class method without overriding the base class method.

I've never encountered a situation where hiding a method was the best choice available. Are there any situations where method hiding is the best choice?

ScottS
  • 8,455
  • 3
  • 30
  • 50
  • Return type co-variance is clearly the common use case. I have in fact encountered that situation more than once and thought it couldn't be done. Now I know better. Property hiding in controls is a nice little trick. Eric Lippert's GST example makes logical sense, but deviates so far from common OOP idioms that I would be very cautious about using it. – ScottS Apr 19 '10 at 16:38

8 Answers8

21

There are rare, but very good, reasons to use method hiding. Eric Lippert posted a great example on his blog:

interface IEnumerable<T> : IEnumerable { 
  new IEnumerator<T> GetEnumerator(); 
}

However, I think hiding should be the exception, and only used sparingly.

V0ldek
  • 9,623
  • 1
  • 26
  • 57
Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • 2
    Yes, but Eric Lippert comments later with: "Of course, if C# had method return type covariance, this would not have to be a new method. That gives us a larger good reason for method hiding; it allows for something like return type covariance in a language that does not have such a feature." . So the question is: why C# doesn't support return type covariance? – ceztko Jul 19 '11 at 06:52
  • Oh, forgot: I actually have an example of using "new" that I think is better than the GetEnumerator() one. – ceztko Jul 19 '11 at 06:55
19

I tend to use it sometimes for convenience for callers, something like:

abstract public class Animal { }

public class Mouse : Animal { }



public class AnimalTrap
{
    public Animal TrappedAnimal { get; }
}

public class MouseTrap : AnimalTrap
{
    new public Mouse TrappedAnimal
    {
        get { return (Mouse)base.TrappedAnimal; }
    }
}

So the caller doesn't have to cast to Mouse themselves when the derived class guarantees the trapped animal will always be a mouse. And polymorphic functionality stays intact.

herzmeister
  • 11,101
  • 2
  • 41
  • 51
  • 2
    +1 This is a nice clear example of return type covariance that Eric Lippert's blog post talks about. I had to stop and think in order to grok the IEnumerable example, but this is straight forward. – ScottS Apr 18 '10 at 18:31
  • 2
    @ScottS: This is a good example of method hiding but it has nothing to do with return type covariance. In fact, there's no type safety guarantee here, a caller could cast `MouseTrap` back to `AnimalTrap` and put a different type of `Animal` in there. – Aaronaught Apr 19 '10 at 16:35
  • @Aaronaught, my understanding of return type covariance is simply changing a methods return type in a derived class. Am I missing something? This emulation of return type co-variance does require that the new return type can be cast to be compatible with it's parent(s) return type(s). Presumably MouseTrap has some logic that only allows it to trap mice. Then you can call AnimalTrap.TrappedAnimal on an instance of MouseTrap and you will safely get a Mouse. – ScottS Apr 19 '10 at 16:57
  • 1
    @ScottS: The concept of covariant return types applies to overridden methods - if you can override the base method, but return a more specific type than the base class, that means the language allows covariant return types. (Incidentally, C# doesn't, although it supports other types of co/contra-variance.) Method hiding isn't covariance - you could have a method declared with `new` return any type at all. – Aaronaught Apr 19 '10 at 17:11
  • And @ScottS - it's not "safe" either, the base `AnimalTrap` is not guaranteed to contain an instance of `Mouse`, so this could quite possibly throw an `InvalidCastException` under the wrong circumstances. The method is just there for convenience, so callers who already know that it's a `MouseTrap` don't have to keep writing casts. – Aaronaught Apr 19 '10 at 17:15
  • @Aaronaught, I agree this is not true return type co-variance, but is as close of facsimile to return type co-variance that c# supports. If you need return type co-variance in c# this appears to be the best technique to apply. As for the invalid cast, I was assuming that the omitted code that traps animals would ensure that mouse traps only trap mice, thus guaranteeing the cast will not be a problem. – ScottS Apr 19 '10 at 17:44
  • The example above can easily be changed to generic and use a type parameter. Result: a mouse would always be a mouse. This makes the "new" keyword redundant in this example. I still think that "new" is never a good choice because there are better ways. – Krumelur Dec 19 '13 at 12:25
  • If you have control over the source of AnimalTrap, why not create a generic `class AnimalTrap where TAnimal : Animal { ... }`? If you really want to have a non-generic animal trap, you can inherit the generic class like so: `class AnimalTrap : AnimalTrap { ... }`. – Nullius Oct 25 '17 at 08:22
14

It's often a good choice when you're creating custom controls, and want to prevent certain properties from appearing in the designer. Sometimes the properties aren't overridable, but the designer doesn't care about that, it only cares whether or not the lowest-level public property has the [Browsable] attribute.

For example, let's say that your control doesn't support padding. The Control.Padding property isn't overridable. But you also know that nothing bad is going to happen if somebody sets the padding, it's just that the property doesn't do anything, so you don't want your users to see it in the designer and think that it actually works. So, hide it:

public class MyControl : Control
{
    [Browsable(false)]
    public new Padding Padding
    {
        get { return base.Padding; }
        set { base.Padding = value; }
    }
}

In this case, we're literally using member hiding to hide the member - from the designer.

As an aside, I'm aware that there are other means of achieving this goal - this is just one possible option.

Aaronaught
  • 120,909
  • 25
  • 266
  • 342
  • I've been using this method to hide a property. What are these other means that you talk about? do you have a link? – Pierre-Alain Vigeant Apr 18 '10 at 18:13
  • @Pierre: You can also implement your own `TypeDescriptor` or `TypeConverter`. The weakness (or strength, depending on your requirements) of that method is that it's opt-in, whereas the member-hiding version is opt-out. – Aaronaught Apr 18 '10 at 18:16
6

The most common example I can think of here is things like DbCommand vs SqlCommand; the concrete types (SqlCommand etc) generally do a lot of method hiding to make the return types of properties / methods display the correct implementation type. This is because the related objects themselves have additional (implementation-specific) features, and the caller doesn't want to have to cast every time they call do anything.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
4

Yes, if you are, for example, just a consumer of a base class and a new version of base class is published that all of a sudden has the method with the exact same signature as one of the methods that you already implemented in your derived class, you need to be able to hide the base class method and you use new to make it clear that you are hiding the base class method...

Dean Kuga
  • 11,878
  • 8
  • 54
  • 108
  • 1
    This is the one legitimate use I was aware of when I asked the question. I would go to great lengths to change method names and avoid the need for new. If I could not change the name, I would probably introduce a method with a new name and mark the conflicting method as deprecated at the same time as adding new to hide the base method. – ScottS Apr 18 '10 at 18:40
  • 1
    Even worse than the possibility of a base-class adding a method with the same name and signature would be the possibility of a the base-class adding an identically-named method with a *different* signature. If `DerivedFoo` has a `DoSomething(double)` method, and a future version of `Foo` adds a `DoSomething(int)` method, code might expect `derivedThing.DoSomething(4)` to invoke the derived-class method, but the new overload in the base class could be considered a "better match". Not all variations on this problem will cause compiler diagnostics. – supercat Feb 02 '13 at 20:00
1

I had to resort to method hiding once. I was using a a 3rd party library which provided a method that was non-virtual (That's the key to the whole thing). It was a method that allocated an instance of something. But I needed to extend the functionality of that method.

So I used the 'new' keyword to hide the base class implementation and provide my own in a derived class. How that doesn't mean I didn't call the base class method. In fact I did call the base-class method, but I did other stuff in my method too, and everything worked out alright in the end.

So I'd say the reasons would be the following:

  1. A base class is in a 3rd party library that you have no control over.
  2. A base class has a non-virtual method that you need to override.
  3. Always pay special attention to extending the functionality not replacing it.
  4. And always use this a last resort when stuck.... :)

My 2 cents...

C.J.
  • 15,637
  • 9
  • 61
  • 77
1

I recently had a case where the 'new' keyword was quite useful. I was writing unit tests for methods in a legacy code base and some of the methods in classes I was writing tests for had external dependencies hidden inside the methods. Including a mocking framework to solve the problem seemed unnecessary at the time, so instead of using a mocking framework I inherited the class I wanted to test inside the unit test class. However, the parent method was not virtual so it could not be overridden. My first solution was to just simply add the virtual keyword to the original method to allow it to be overridden and the tests worked great. Even though it worked, I don't think that adding virtual keywords to method signatures only because of the need to "mock" it in a unit test is a good design decision (but I might be wrong). Instead the usage of 'new' keyword in the child class enabled me to 'get rid of' the parent methods dependencies by hiding the original method with a method with static return values, thus writing fast unit tests for rest of the methods worked as well as when changing non-virtual methods to virtual methods.

In general, I am not sure this technique can be considered good practice. However, using this kind of technique might be very useful when writing a test suite to ease refactoring when working with legacy code with many dependencies and does not have an automated test suite to start with. The tests can most likely be improved when the refactoring work is completed.

EDIT: Because method hiding only occurs in the private inherited class it should not cause any confusion that might occur in other use cases.

Spacy
  • 70
  • 1
  • 8
  • Your answer read my mind nearly word for word. Might not be a "best" practice, but this seems to solve a real issue in a thoughtful way. I agree adding the virtual keyword to the original method is not a good idea because you are driving the design of the higher-level, more abstract class by the implementation of the lower-level mock class. – Nicholas Miller Nov 02 '18 at 21:05
0

One time I've used it is in a custom winforms control. My custom control overrides the Text property, and I want to raise an event whenever it changes. The base Control class comes with a TextChanged event, however the base event has attributes slapped on it to prevent it from showing up in the designer or in intellisense. Since we are using the event in our custom control, this is undesirable, so we do the following:

    [Browsable(true)]
    [EditorBrowsable(EditorBrowsableState.Always)]
    public new event EventHandler TextChanged
    {
        add { base.TextChanged += value; }
        remove { base.TextChanged -= value; }
    }

Event handlers will still get added to the same event regardless of the type of reference that is used to access it, but references of derived-type will have the TextChanged event show up in intellisense, and when our control is placed on a form in the designer, the TextChanged event will show up in the properties window.

Newell Clark
  • 345
  • 2
  • 13