There are cases where the design of an abstract class requires that some static properties should be changed by the child classes (using the new keyword) where as the static functions remained the same. While testing, I realized that the static functions that were declared in the abstract class used the values of the static properties from the abstract class ignoring the new statement.
public abstract class abstractClass { public abstractClass() { } public abstractClass(int num) { ID = num; } public int ID = 1; public static int StaticID = 10; public int GetIDSquare() { return ID * ID; } public int GetStaticIDSquare() { return StaticID * StaticID; } } public class SimpleClass : abstractClass { public static new int StaticID = 20; public SimpleClass(int num) : base(num) { } }
In the above example, calling the SimpleClass.GetStaticIDSquare will return 100 and not 400. This is expected, since this is how polymorphism works in most languages. C++, C# and Java have the same behaviour, where as Delphi supports polymorphism in static methods as well.
Some people would argue that if you reached this point your design probably has a flaw and you need to change it. This is a valid argument, but in some cases a less correct approach is really convenient, especially if these classes are not a part of your core architecture but some helper classes (e.g. a Data Access Layer) that will simply make the developer’s job more easy.
In order to have our static property overridden, we will use delegates. In our scenario we will change our StaticID property to a function. This function will check for the existence of the overridden function and call that instead. In our example the StaticID property is an integer, which is not nullable (something required to invoke the static method). For this reason we will change its type to string and then will simply add a wrapper method that will make the appropriate conversion. The child class will have to set the string property and not the integer property.
public abstract class abstractClass<T> { public abstractClass() { } public abstractClass(int num) { ID = num; } public int ID = 1; public static int StaticID { get { return Convert.ToInt32(StaticIDStr()); } } public static string StaticIDStr() { return invokeStaticMethod("StaticIDStr", null) as string; } public int GetIDSquare() { return ID * ID; } public int GetStaticIDSquare() { return StaticID * StaticID; } private static Object invokeStaticMethod(String MethodName, Object[] Args) { return typeof(T).InvokeMember(MethodName, BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, Args); } } public class FixedSimpleClass : abstractClass<FixedSimpleClass> { public static new string StaticIDStr() { return "20"; } public FixedSimpleClass(int num) : base(num) { } }
It is not the prettiest solution, but it works and that’s what is important. You can check also these two articles that helped me to come up with this solution. The second link has a few lines that explains why static methods cannot (and should not) be overridden.
Leave a Reply