Reputation: 35963
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.
Upvotes: 1
Views: 517
Reputation: 6775
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.
Upvotes: 1
Reputation: 5327
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();
}
}
Upvotes: 1
Reputation: 1977
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.
Upvotes: 1
Reputation: 68750
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.
Upvotes: 2
Reputation: 727077
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:
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.
Upvotes: 1