Virtual member call in a constructor

后端 未结 18 1842
[愿得一人]
[愿得一人] 2020-11-22 01:27

I\'m getting a warning from ReSharper about a call to a virtual member from my objects constructor.

Why would this be something not to do?

相关标签:
18条回答
  • 2020-11-22 02:08

    Yes, it's generally bad to call virtual method in the constructor.

    At this point, the objet may not be fully constructed yet, and the invariants expected by methods may not hold yet.

    0 讨论(0)
  • 2020-11-22 02:09

    Your constructor may (later, in an extension of your software) be called from the constructor of a subclass that overrides the virtual method. Now not the subclass's implementation of the function, but the implementation of the base class will be called. So it doesn't really make sense to call a virtual function here.

    However, if your design satisfies the Liskov Substitution principle, no harm will be done. Probably that's why it's tolerated - a warning, not an error.

    0 讨论(0)
  • 2020-11-22 02:13

    There's a difference between C++ and C# in this specific case. In C++ the object is not initialized and therefore it is unsafe to call a virutal function inside a constructor. In C# when a class object is created all its members are zero initialized. It is possible to call a virtual function in the constructor but if you'll might access members that are still zero. If you don't need to access members it is quite safe to call a virtual function in C#.

    0 讨论(0)
  • 2020-11-22 02:15

    Just to add my thoughts. If you always initialize the private field when define it, this problem should be avoid. At least below code works like a charm:

    class Parent
    {
        public Parent()
        {
            DoSomething();
        }
        protected virtual void DoSomething()
        {
        }
    }
    
    class Child : Parent
    {
        private string foo = "HELLO";
        public Child() { /*Originally foo initialized here. Removed.*/ }
        protected override void DoSomething()
        {
            Console.WriteLine(foo.ToLower());
        }
    }
    
    0 讨论(0)
  • 2020-11-22 02:18

    The warning is a reminder that virtual members are likely to be overridden on derived class. In that case whatever the parent class did to a virtual member will be undone or changed by overriding child class. Look at the small example blow for clarity

    The parent class below attempts to set value to a virtual member on its constructor. And this will trigger Re-sharper warning, let see on code:

    public class Parent
    {
        public virtual object Obj{get;set;}
        public Parent()
        {
            // Re-sharper warning: this is open to change from 
            // inheriting class overriding virtual member
            this.Obj = new Object();
        }
    }
    

    The child class here overrides the parent property. If this property was not marked virtual the compiler would warn that the property hides property on the parent class and suggest that you add 'new' keyword if it is intentional.

    public class Child: Parent
    {
        public Child():base()
        {
            this.Obj = "Something";
        }
        public override object Obj{get;set;}
    }
    

    Finally the impact on use, the output of the example below abandons the initial value set by parent class constructor. And this is what Re-sharper attempts to to warn you, values set on the Parent class constructor are open to be overwritten by the child class constructor which is called right after the parent class constructor.

    public class Program
    {
        public static void Main()
        {
            var child = new Child();
            // anything that is done on parent virtual member is destroyed
            Console.WriteLine(child.Obj);
            // Output: "Something"
        }
    } 
    
    0 讨论(0)
  • 2020-11-22 02:19

    I would just add an Initialize() method to the base class and then call that from derived constructors. That method will call any virtual/abstract methods/properties AFTER all of the constructors have been executed :)

    0 讨论(0)
提交回复
热议问题