From the MSDN documentation:
Although you can hide members without the use of the new modifier, the result is a warning. If you use new to explicitly hide a member, it suppresses this warning and documents the fact that the derived version is intended as a replacement.
Hiding class members can lead to misunderstandings and subtle errors. Hence the compiler warns you and requires you to make your intention of a possibly harmful member hiding explicit by using the "new" modifier. This prevents an accidental hiding of a base type member from being unnoticed.
See this little example of how problems can sneak into your code when hiding members:
public abstract class A
{
public int Value = 0;
}
public class B : A
{
// This hides the Value member from the base type A
public new int Value = 0;
}
static void SetValue(B obj, int value)
{
obj.Value = value;
}
static void AddToValue(A obj, int value)
{
obj.Value += value;
}
static void Main(string[] args)
{
B obj = new B();
SetValue(obj, 11);
AddToValue(obj, 5);
Console.Out.WriteLine("obj.Value = " + obj.Value);
Console.Out.WriteLine("((A) obj).Value = " + ((A) obj).Value);
Console.Out.WriteLine("((B) obj).Value = " + ((B) obj).Value);
}
This will output:
obj.Value = 11
((A) obj).Value = 5
((B) obj).Value = 11
Just by looking at the flow of the Main method, you might think that at the end of the method the value of obj.Value is 16 (=11+5). But it isn't - it is even worse: depending on how you access the Value member you will encounter different values.
Now, in this small example, the reason(s) of why the output is not the same and not the expected value in all cases might be easy and quickly to spot. But imagine larger software projects with many classes, lots of inheritances, method arguments being of abstract base class or interface types, 3rd-party class library, you name it..., and the problems caused by hidden members might become much more difficult to identify.