namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
B obj = new B();
}
}
class A
{
public A()
{
Console.WriteLine("A's Constructor");
myMethod();
}
protected virtual void myMethod()
{
Console.WriteLine("A's member executed");
}
}
class B : A
{
public B()
{
Console.WriteLine("B's Constructor");
}
protected override void myMethod()
{
Console.WriteLine("B's member executed");
}
}
}
In the above code, in base class constructor, we are calling virtual member myMethod(). Since we are instantiating B, B's definition of myMethod would be used and you should observe the following output:
A's Constructor
B's member executed
B's Constructor
Some of you might be thinking why we are able to call B's implementation even when it's constructor hasn't yet been executed. Well it is just because object initialization is different than execution of constructor. Constructors are executed downward in specialization hierarchy but the direction of object initialization is opposite to this.
You might still not be able to find out any issue with this. The issue is when child's overriden member uses some of it's own instance fields. Let's see this in an example:
class B : A
{
string testString;
public B()
{
Console.WriteLine("B's Constructor");
testString = "Child string";
}
protected override void myMethod()
{
Console.WriteLine("B's member executed");
Console.WriteLine(testString.ToLower());
}
}
Here we have introduced a string, named testString in child class B. We are accessing this member in virtual method "myMethod". As soon as the control reaches the second line in myMethod() in B, it results in an exception.
Now it is a genuine requirement to allow child class to initialize it's members. In order to allow that, we might provide another virtual method which is executed before the required virtual member in the following manner:
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
B obj = new B();
}
}
class A
{
public A()
{
Console.WriteLine("A's Constructor");
initializeMembers();
myMethod();
}
protected virtual void initializeMembers()
{
}
protected virtual void myMethod()
{
Console.WriteLine("A's member executed");
}
}
class B : A
{
string testString;
public B()
{
Console.WriteLine("B's Constructor");
testString = "Child string";
}
protected override void myMethod()
{
Console.WriteLine("B's member executed");
Console.WriteLine(testString.ToLower());
}
protected override void initializeMembers()
{
base.initializeMembers();
testString = "Updated child string";
}
}
}
Now everything works fine. Not only we are able to access child class members but we are also able to initialize them before its constructor execution. Though this work around provides a workable solution, it is not recommended to use virtual members in constructors unless the class is itself sealed or the member is sealed. This would prevent the resulting exception. This is why most static analysis and productivity tools including ReSharper warns in this situation.
2 comments:
it seems that you forgot to add inheritance between class B and class A in the first code listing
class B (: A)
section in parentheses is missing
You are right! Thanks for the correction.
Post a Comment