Domanda

What is the actual practical use of the 'new' modifier?

public class Base
{
    public void Say()
    {
        Console.WriteLine("Base");
    }
}

public class Derived:Base
{
    public new void Say()
    {
        Console.WriteLine("Derived");
    }
}

It wouldn't it better if this just fails to compile? This code:

        Derived d = new Derived();
        d.Say();
        ((Base)d).Say();

Returns

 Derived
 Base

Doesn't this break the Liskov substitution principle?

Cheers.

È stato utile?

Soluzione

Regarding LSP

That doesn't break the LSP. The LSP states that if Derived is a subtype of Base, then any code depending on Base (e.g, a method with a Base parameter, like void DoSomething(Base b)) can be replaced with an instance of Derived, without any surprising effects.

And as you pointed out, if you assign an instance of Derived to a Base variable, the Base implementation will be called.

That's the expected behaviour, since Say is not virtual. This means that code written against a Base variable, expects the Base implementation to be called.

Practical purpose

You can think of new methods as a way to circumvent a non-overridable method - with a caveat! You'll have to program against that specific type - not its interface.

Altri suggerimenti

A method in derived class is considered "related" to a method in its base class if it has the same name and parameter list. Compiler designers have two ways of dealing with such related methods:

  1. Rely upon a convention - for example, they could declare such methods an override; Java does that.
  2. Request explicit direction from programmers - C# designers took that route: they ask programmers to designate related methods with virtual/override, and unrelated methods with new.

The first way of handling elated methods leaves programmers no choice: if they want an unrelated methods, they must give it a different name. The second way leaves the choice with the programmer, at the expense of being more verbose.

Essentially, the new keyword lets you communicate to the compiler that the method that you've added is unrelated to a method in the base class that has the same name and parameters.

Doesn't this break the Liskov substitution principle?

Arguably, it does not: the fact that the derived class has introduced a method with the same name and parameters, which the programmer explicitly designated as unrelated to the method in the base, does not change anything in the behavior of the derived class in situations when it is used as a stand-in for its base class.

It simply allows the user to redefine the method in the base class. Naturally, had the developer foreseen this happenstance, you'd hope they'd have coded it as virtual (for a default implementation) or abstract (where any implementation needs to be specified).

The LSP simply put just requires that a base class and sub class can be used interchangeably so this doesn't violate the principle as far as I can see.

A foible of C# is that only one class can be inherited so a case such as this should be relatively rare for complex systems where the multiple implementation of interfaces would be preferred.

This can be useful when Base and clients of Derived are out of your control. Suppose you started with this.


public class Base
{
  // there is no Say method in Base!
}

public class Derived:Base
{
    public /*new*/ void Say() // we don't need new here
    {
        Console.WriteLine("Derived");
    }
}

Then someday those who are in charge of Base added cool Say method there. You could have renamed Derived.Say, but it's already used elsewhere by code you cannot change. So you use new to avoid breaking changes in Derived.


public class Base
{
    public void Say()
    {
        Console.WriteLine("Base");
    }
}

public class Derived:Base
{
    public new void Say()
    {
        Console.WriteLine("Derived");
    }
}

public class SomeClient
{
    public void Run()
    {
        var d = new Derived();
        d.Say();
    }
}

Though it's not a good practice to do it, I can see it being useful when you inherit from a third party assembly (i.e. Code you don't have control over ) and you want to have a different behavior for a method.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top