Wednesday, October 27, 2004

VJs Tip Of The Day - October 27th 2004

MethodBase.IsFinal & MethodBase.IsVirtual

MethodBase is a class in System.Reflection. IsFinal is a boolean property of this class. If you dynamically want to find out whether a given method can be overridden or not then merely checking IsVirtual flag is not good enough... Look at the following example... Again out of the box running code... Just copy in IDE and run...

Below is our BaseClass... It implements IComparer... It might be any interface I am just taking IComparer for example...

using System.Collections;
public class BaseClass : IComparer
{

public int Compare(object x, object y)
{
return 0;
}

}
Below is our DerivedClass... It does not implement IComparer as its base already does... But still it wants a Compare method in its own way... So it needs to hide the base implementation (not a good OO practice always but this is for example sake)

public class DerivedClass : BaseClass
{
//Note if you do not use new the Derived class will not compile
public new int Compare(object x, object y)
{
return 1;
}

}

So now as usual our quick windows form app... Add reference to System.Reflection and also our class library which contains above two classes in here...

using System.Reflection;

private string CallMeOnButtonClick()
{
string displayText = String.Empty;

Type t = typeof(VirtualTest.BaseClass);
displayText += t.GetMethod("Compare").IsVirtual.ToString();
displayText += t.GetMethod("Compare").IsFinal.ToString();

Type t1 = typeof(VirtualTest.DerivedClass);
displayText += t1.GetMethod("Compare").IsFinal.ToString();
displayText += t1.GetMethod("Compare").IsVirtual.ToString();

}
The displayText at the end will be TrueTrueFalseFalse...

What does this mean... in BaseClass we did not mark Compare method to be Virtual still it came out to be Virtual... This is because it is a implementation of an Interface and so it is automatically marked virtual inside Interface... So it returns us that the method was actually virtual....
Now even the IsFinal flag for BaseClass.Compare is True... This means that even though it might be internally virtual but still it is the final implementation of the method... You can no more override it in the derived class... If you try to put overrides keyword in DerivedClass's Compare method declaration it will not compile giving error that the method is not marked virtual or abstract in the base class... Do note that your IsVirtual value was true for this method though... :-)

In case of Derived class we get IsVirtual to be false, it is obvious because we have shadowed the base implementation and also have no virtual keyword associated with the method here... IsFinal is false here as it is not coming from a interface or any such source which forces it to be true...

So in short... unless and until you do not have both - "IsFinal as False" and "IsVirtual as True" you can override a method...

PS: If you want to get more inquisitive try to derive a third class here... Mark your method as "virtual new" in 2nd Class and override in 3rd class... Try to study the results... If you felt a little bit confused over the whole explanation then try and feel what "Flags" do to any class... The more flags you have more your reader is going to confused... Btw, did we talk about "MethodBase.IsHideBySig" anytime... That also plays a role in above examples... :-)

PPS: Typing the line "?System.Reflection.Person.MoodInfo().GetMood("Vishal",System.Reflection.BindingFlags.Today)" in the immediate window of VS.Net 2003 debugger resulted into "Bad, Very Bad, Very Very Bad, Very Very Very Bad, Very Very Very Bad.................................................................................." :-)

No comments: