Monday, April 24, 2017

C# - Do not call virtual methods in Constructors ( CA2214 )

Calling virtual methods in constructors can create potential problems. See the following sample code

public class BaseClassType
    {
        public BaseClassType()
        {
            DoCall();
        }
        public virtual void DoCall()
        {
            Console.WriteLine("BaseClass DoCall");
        }
    }
    public class DerivedClassType : BaseClassType
    {
        private string type;
        public DerivedClassType()
        {
            type = "Derived";
        }
        public override void DoCall()
        {
            Console.WriteLine("The type is:" + type.ToUpper());
        }
    } 
Create DerivedClassType object in Main()
DerivedClassType derivedObj = new DerivedClassType(); 
Output: NullReferenceException

Execution Flow:
  1. When an object constructed in C#, the initializers run in order from the most derived class to the base class, and then constuctors run in order from the base class to the most derived class. 
  2. When we create the new instance of DerivedClassType, the default parameterless constructor in BaseClassType is called first. i.e. control goes to DoCall() function 
  3. When BaseClassType calls DoCall(), it is virtual method and looks for overridden method . So, it is directed to the DoCall() in DerivedClassTpe. 
  4. However, at this point the code in DerivedClassType constructor has not yet executed, and so the type variable is still referring null. 
  5. When we call type.ToUpper(), It gives null reference exception . I.e. DoCall() method executing before DerivedClassType constructor execution. 
  6. check VS code analysis rule CA2214
 I would recommend convert VS code analysis rule CA2214 from warning to error.

Check another example : 
 public class BadlyConstructedType
    {   protected  string initialized = "No";        
        public BadlyConstructedType()
        {   Console.WriteLine("Calling base ctor.");
            DoSomething();
        }
        public virtual void DoSomething()
        {   Console.WriteLine ("Base DoSomething");
        }
    }    
    public class DerivedType : BadlyConstructedType
    {   public DerivedType ()
        {   Console.WriteLine("Calling derived ctor.");
            initialized = "Yes";
        }
        public override void DoSomething()
        {  Console.WriteLine("Derived DoSomething - initialized ? {0}", initialized);
        }
    }

DerivedType derivedInstance = new DerivedType();

Output :
Calling base ctor.
Derived DoSomething - initialized ? No
Calling derived ctor.

Happy Coding :)

No comments:

Post a Comment