Be careful using new modifier in your C# code






3.30/5 (12 votes)
Using new modifier in your C# code could result in unexpected result.
Introduction
One of purposes of the new
keyword in C# is to be used as a modifier on specific member in derived class in order to hide the member in base class that has same name. In many ways, it works very similar to override
modifier which is to override a virtual or implement an abstract member in base class. However, using new
keyword may result in unexpected result, which is the issue we are going to take a look in this article.
The issue
Let us take a look at following example. We have a Mother
class and a Son
class. In class Son
, the GetName() method is modified with new
keyword.
public class Mother
{
public virtual string GetName()
{
return "Lisa";
}
}
public class Son : Mother
{
public new string GetName() // Here
{
return "Robert";
}
}
Next, consider following simple code:
using System;
public class Program
{
public static void Main()
{
var son = new Son();
Console.WriteLine(son.GetName()); // Robert
}
}
Everything seems fine. However, if we change the code to below, the issue occurs where the return value of GetName()
method changes to "Lisa".
using System;
public class Program
{
public static void Main()
{
var son = new Son();
Console.WriteLine((son as Mother).GetName()); // Lisa
}
}
How did this happen?
The fact is, the new
modifier does not actually override the method in base class. As we have mentioned previously, the keyword just hides the method from base class in Son
class. When the external caller casts derived class to its base class, the GetName()
method is actually the method that belongs to base class.
You can now expect that when whole source code is getting complicated with lots of type inheritance, this could lead to unexpected behavior.
Note that this issue will not occur in virtual
/override
context. So following code works:
using System;
public class Program
{
public static void Main()
{
var daughter = new Daughter();
Console.WriteLine(daughter.GetName()); // Jennifer
Console.WriteLine((daughter as Mother).GetName()); // Jennifer
}
}
public class Mother
{
public virtual string GetName()
{
return "Lisa";
}
}
public class Daughter
{
public override string GetName() // Note the difference
{
return "Jennifer";
}
}
How about interfaces?
Let us take a look at a more complicated example. We have Mother
, Son
and Daughter
classes and an IFamily
array that consists of each instance. Then we call GetName()
method one by one.
using System; // Namespace in this example omitted.
public class Program
{
public static void Main()
{
var array = new IFamily[]{ new Mother(), new Son(), new Daughter() };
Console.WriteLine(array[0].GetName()); // Lisa
Console.WriteLine(array[1].GetName()); // Lisa
Console.WriteLine(array[2].GetName()); // Jennifer
}
}
public interface IFamily
{
string GetName();
}
public class Mother : IFamily
{
public virtual string GetName()
{
return "Lisa";
}
}
public class Son : Mother
{
public new string GetName() // Note the difference
{
return "Robert";
}
}
public class Daughter : Mother
{
public override string GetName() // Note the difference
{
return "Jennifer";
}
}
Now the same issue occurs again as we can see the return value of second GetName()
call is supposed to be "Robert". The reason is, for the class Son
, the class that actually implements IFamily
interface is its base class Mother
. Thus, when external caller casts all these instances to IFamily
instances, Son
.GetName()
method will not be reached.
Conclusion
Remember that the new
modifier does not actually override the method in base class but virtual
/override
scenario does. When using new
modifier, the behavior highly depends on how external caller uses your classes. Casting the instance to base class will have the member in derived class never be called.
History
2017-11-19 Initial post.
2017-11-20 Fix grammatical errors.