MustOverride Generic Declaration

So why is it not allowed to have Shared MustOverride / Overridable ? Some argue that redefinition is related to inheritance, which does not make sense in the case of Shared members, because instantiation is not involved. Here is one example where I need it:

My base class, DrawingObject defines a Shared member named TypeName that must be implemented by each child class to return a unique identification string that is different for each child type, but the same for all instances of the same child type. Now this requires the TypeName property to be defined as Shared and Overridable . Or is there a better way to do this?

Base class

 Public MustInherit Class DrawingObject Public MustOverride ReadOnly Property TypeName As String End Class 

Child class

 Public Class Rectangle Inherits DrawingObject Public Overrides ReadOnly Property TypeName As String Get Return A_CONST_STRING_DEFINED_IN_THIS_CLASS End Get End Property End Class 

This code works fine, but ideally TypeName should have been Shared since it returns Const .

+5
source share
2 answers

The whole point of redefinition is to facilitate polymorphism. You are passing an object around, and the way it behaves depends on the type of object, not the type of link. If you call Shared participants, you call them on a type, not an object, so polymorphism does not apply, so redefining sentences has no advantages.

In your case, if you want to get the TypeName object without knowing what type of this object is at runtime, then overriding this property makes sense. No matter where you are, you can get this property, and you will get a type name for this object. When using the Shared member, you will get a property of a certain type so that you can simply get a property of that type.

The requested example:

Let's say that you have forms that can draw on the screen. You can start with the Shape base class with the Shape base class using the Draw method, and then inherit this class, for example, in the Square and Circle classes. Then you might have a method like this:

 Public Sub DrawShape(myShape As Shape) myShape.Draw() End Sub 

In this case, it makes sense to override the Draw method in derived classes, because it allows you to simply call Draw wherever you have the Shape link and know that it will be drawn correctly. If this method is passed to a Square , then a square will be drawn, and if it is passed to a Circle , then a circle will be selected, but the method should not know or care, thanks to polymorphism.

If what you were proposing was possible, but Draw was Shared , you would need to call Square.Draw every time you would like to draw a square and Circle.Draw every time you wanted to draw a circle. The whole point of redefinition is that you should be able to call the method by reference of the base type and get the functionality defined in the derived type. In your scenario, you will need to call the method on the derived type to get the functionality defined on the derived type, so you get no benefit. You could not just name Shape.Draw and have something useful. Among other things, which derived class will he choose?

+4
source

You are trying to create a self-describing class.

There are 3 methods:

  • Enabling dependencies: use a structure such as a whole (heavy, but maybe what you want is valid)
  • Custom Attributes: Add Metadata to a Class and Scan Metadata
  • Self-registering classes (create instances and destroy each subclass to access mustoverride properties). Uses a factory pattern.

Custom Attributes:

This is a simple example I made:

 Imports System.Linq Imports System.Runtime.CompilerServices <AttributeUsage(System.AttributeTargets.[Class])> Public Class SelfDescribingClassAttribute Inherits System.Attribute Public Property Name As String Public Sub New(Name As String) Me.Name = Name End Sub End Class <SelfDescribingClassAttribute("ExampleClassName")> Public Class ExampleClass End Class Public Module SelfDescribingClassTools Public Function GetNameOfSelfDescribingClass(ClassType As Type) As String Try GetNameOfSelfDescribingClass = ClassType.GetAttributeValue(Function(SelfDescribingClass As SelfDescribingClassAttribute) SelfDescribingClass.Name) Catch ex As Exception Return String.Empty End Try End Function Public Function GetDictionaryOfSelfDescribingClasses(Of T)() As Dictionary(Of String, Type) GetDictionaryOfSelfDescribingClasses = New Dictionary(Of String, Type) Dim Subclasses As Type() = GetSubClasses(Of T)() For Each Subclass As Type In Subclasses Try Dim name As String = GetNameOfSelfDescribingClass(Subclass) If Not String.IsNullOrWhiteSpace(name) Then GetDictionaryOfSelfDescribingClasses.Add(name, Subclass) End If Catch ex As Exception Debug.Print(ex.ToString) End Try Next End Function Public Function GetSubClasses(Of T)() As Type() Dim baseType As Type = GetType(T) Dim assembly As Reflection.Assembly = baseType.Assembly Return assembly.GetTypes().Where(Function(x) x.IsSubclassOf(baseType)) End Function <Extension()> Function GetAttributeValue(Of TAttribute As Attribute, TValue)(ByVal type As Type, ByVal valueSelector As Func(Of TAttribute, TValue)) As TValue Dim att = TryCast(type.GetCustomAttributes(GetType(TAttribute), True).FirstOrDefault(), TAttribute) If att IsNot Nothing Then Return valueSelector(att) End If Return Nothing End Function End Module 

Self-registration classes:

This is a really good post with examples: http://www.jkfill.com/2010/12/29/self-registering-factories-in-c-sharp/

From the website:

DataType.cs:

 using System; using System.Collections.Generic; using System.Reflection; namespace SelfRegisteringFactory { public abstract class DataType { public static DataType Create(string typeName) { Type derivedType = null; if (sTypeMap.TryGetValue(typeName, out derivedType)) { return System.Activator.CreateInstance(derivedType) as DataType; } return null; } public abstract string GetDefaultValue(); protected abstract string GetTypeName(); private static Dictionary<string, Type> sTypeMap = CreateTypeMap(); private static Dictionary<string, Type> CreateTypeMap() { Dictionary<string, Type> typeMap = new Dictionary<string, Type>(); Assembly currAssembly = Assembly.GetExecutingAssembly(); Type baseType = typeof(DataType); foreach (Type type in currAssembly.GetTypes()) { if (!type.IsClass || type.IsAbstract || !type.IsSubclassOf(baseType)) { continue; } DataType derivedObject = System.Activator.CreateInstance(type) as DataType; if (derivedObject != null) { typeMap.Add( derivedObject.GetTypeName(), derivedObject.GetType()); } } return typeMap; } } } 

BooleanDataType.cs:

 using System; namespace SelfRegisteringFactory { public class BooleanDataType : DataType { public BooleanDataType() { } public override string GetDefaultValue() { return "false"; } protected override string GetTypeName() { return "bool"; } } } 

IntegerDataType.cs:

 using System; namespace SelfRegisteringFactory { public class IntegerDataType : DataType { public IntegerDataType () { } public override string GetDefaultValue () { return "0"; } protected override string GetTypeName () { return "int"; } } } 

Main.cs:

 using System; namespace SelfRegisteringFactory { class MainClass { public static void Main (string[] args) { PrintDefaultForType("bool"); PrintDefaultForType("int"); } public static void PrintDefaultForType(string typeName) { DataType dataType = DataType.Create(typeName); if (dataType != null) { Console.WriteLine(dataType.GetDefaultValue()); } else { Console.WriteLine("unknown"); } } } } 
0
source

All Articles