Click here to Skip to main content
15,867,568 members
Articles / Programming Languages / C#

Be careful using new modifier in your C# code

Rate me:
Please Sign up or sign in to vote.
3.30/5 (12 votes)
19 Nov 2017CPOL2 min read 17.2K   1   5
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.

C#
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:

C#
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".

C#
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:

C#
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.

C#
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 Sonthe 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. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Taiwan Taiwan
Back-end developer, English learner, drummer, game addict, Jazz fan, author of LINQ to A*

Comments and Discussions

 
QuestionGreat Pin
mehdi-ichka8-Mar-21 5:50
mehdi-ichka8-Mar-21 5:50 
PraisePerfect explanation Pin
dibley197312-Jun-18 21:20
dibley197312-Jun-18 21:20 
QuestionUsing the "new" keyword is an indication of bad architecture Pin
Marc Clifton20-Nov-17 2:28
mvaMarc Clifton20-Nov-17 2:28 
AnswerRe: Using the "new" keyword is an indication of bad architecture Pin
Robert Vandenberg Huang20-Nov-17 14:50
professionalRobert Vandenberg Huang20-Nov-17 14:50 
GeneralCan't agree more!!! Pin
Stylianos Polychroniadis19-Nov-17 20:04
Stylianos Polychroniadis19-Nov-17 20:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.