Having read through these answers, they explain pretty well what the new operator does, but I don't see any clear answer to this part of the OP's question:
do you know a scenario where hiding in an interface would be useful ?
In summary, it all boils down to testability and reuse. By splitting up interfaces into smaller chunks, and adhering to the Interface Separation Principle, we can make users of our classes minimally dependent on irrelevant detail and maximally decoupled, which provides us with more reusability options and an easier time when it comes to testing.
In general, the new operator comes into play here when we need to branch our interface type-hierarchy in a way where method collisions are unavoidable. That all sounds a bit abstract and it's hard to explain, so I created what I believe is a minimal example where we want to split our interface type hierarchy into two, while there's a common shared method. I put the code on .NET fiddle:
https://dotnetfiddle.net/kRQpoU
Here it is again:
using System;
public class Program
{
public static void Main()
{
//Simple usage
var simpleCuboid = new MockCuboidSimple();
var heightUser = new HeightUserEntangled();
var volumeUser = new VolumeUserEntangled();
Console.WriteLine("*** Simple Case ***");
Console.WriteLine(heightUser.PrintHeight(simpleCuboid));
Console.WriteLine(volumeUser.PrintVolume(simpleCuboid));
//Smart usage - the same behaviour, but more testable behind the scenes!
var smartCuboid = new MockCuboidSmart();
var heightUserSmart = new HeightUserSmart();
var volumeUserSmart = new VolumeUserSmart();
Console.WriteLine("*** smart Case ***");
Console.WriteLine(heightUserSmart.PrintHeight(smartCuboid));
Console.WriteLine(volumeUserSmart.PrintVolume(smartCuboid));
}
}
//Disentangled
class VolumeUserSmart
{
public string PrintVolume(IThingWithVolume volumeThing)
{
return string.Format("Object {0} has volume {1}", volumeThing.Name, volumeThing.Volume);
}
}
class HeightUserSmart
{
public string PrintHeight(IThingWithHeight heightThing)
{
return string.Format("Object {0} has height {1}", heightThing.Name, heightThing.Height);
}
}
class MockCuboidSmart : ICuboidSmart
{
public string Name => "Mrs. Cuboid";
public double Height => 3.333;
public double Width => 31.23432;
public double Length => 123.12;
public double Volume => Height * Width * Length;
}
interface ICuboidSmart : IThingWithHeight, IThingWithVolume
{
//Here's where we use new, to be explicit about our intentions
new string Name {get;}
double Width {get;}
double Length {get;}
//Potentially more methods here using external types over which we have no control - hard to mock up for testing
}
interface IThingWithHeight
{
string Name {get;}
double Height {get;}
}
interface IThingWithVolume
{
string Name {get;}
double Volume {get;}
}
//Entangled
class VolumeUserEntangled
{
public string PrintVolume(ICuboidSimple cuboid)
{
return string.Format("Object {0} has volume {1}", cuboid.Name, cuboid.Volume);
}
}
class HeightUserEntangled
{
public string PrintHeight(ICuboidSimple cuboid)
{
return string.Format("Object {0} has height {1}", cuboid.Name, cuboid.Height);
}
}
class MockCuboidSimple : ICuboidSimple
{
public string Name => "Mrs. Cuboid";
public double Height => 3.333;
public double Width => 31.23432;
public double Length => 123.12;
public double Volume => Height * Width * Length;
}
interface ICuboidSimple
{
string Name {get;}
double Height {get;}
double Width {get;}
double Length {get;}
double Volume {get;}
//Potentially more methods here using external types over which we have no control - hard to mock up for testing
}
Notice that VolumeUserSmart
and HeightUserSmart
only depend on fragments of the ICuboidSmart
interface that they care about, namely IThingWithHeight
and IThingWithVolume
. This way, they can be maximally reused, e.g. for shapes other than cuboids, and also can be more easily tested. The last point is, I find in practice, crucial. It's much easier to mock up an interface with fewer methods, especially if the methods in the main interface type contain references to types that we don't control. Of course, one can always get around this with a mocking framework, but I prefer to keep the code clean at its core.
So where does the new
keyword fit in here? Well, since VolumeUserSmart
and HeightUserSmart
both need access to the Name
property, we must must declare it in both IThingWithHeight
and IThingWithVolume
. And thus we must redeclare it in the sub-interface ICuboidSmart
, or else we'll get a compiler error complaining about ambiguity. What we're doing in that case is hiding the two versions of Name
defined in IThingWithHeight
and IThingWithVolume
that would otherwise collide. And, like other answers point out, though we don't have to use new
here, we should, to be explicit about our intentions to hide.