Frage Gemeinsame Nutzung von MustOverride wird deklariert


Warum also darf es nicht haben? Shared  MustOverride/Overridable Mitglieder? Einige argumentieren, dass das Überschreiben mit der Vererbung zusammenhängt, was im Falle von Shared Mitglieder, da keine Instanziierung beteiligt ist. Hier ist ein Beispiel wo ich es brauche:

Meine Basisklasse DrawingObject definiert a Shared Mitglied benannt TypeName Dies muss von jeder untergeordneten Klasse implementiert werden, um eine eindeutige Identifikationszeichenfolge zurückzugeben, die für jeden untergeordneten Typ unterschiedlich ist, aber für alle Instanzen eines untergeordneten Typs gleich ist. Jetzt muss ich das haben TypeName Eigenschaft definiert als Shared und Overridable. Oder gibt es einen besseren Weg?

Basisklasse

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

Kinderklasse

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

Dieser Code funktioniert gut, aber im Idealfall TypeName gewesen sein sollte Shared da es a zurückgibt Const.


5
2017-09-08 04:38


Ursprung


Antworten:


Der Hauptpunkt des Übersteuerns ist, Polymorphismus zu erleichtern. Sie übergeben ein Objekt und die Art und Weise, wie es sich verhält, hängt vom Typ des Objekts und nicht vom Typ der Referenz ab. Wenn du anrufst Shared Dann nennt man sie eher einen Typ als ein Objekt, so dass Polymorphie nicht gilt, also hat das Überschreiben keinen Vorteil.

In deinem Fall, wenn du das bekommen willst TypeName eines Objekts, ohne zu wissen, welcher Typ dieses Objekt zur Laufzeit ist, dann würde das Überschreiben dieser Eigenschaft sinnvoll sein. Unabhängig davon, wo Sie sich befinden, können Sie diese Eigenschaft abrufen, und Sie erhalten den Namen des Typs dieses Objekts. Mit einem Shared-Member erhalten Sie die Eigenschaft für einen bestimmten Typ, sodass Sie einfach eine Eigenschaft dieses Typs abrufen können.

Angefordertes Beispiel:

Nehmen wir an, Sie haben eine Form, die sich auf dem Bildschirm zeichnen kann. Sie könnten mit einer Basis beginnen Shape Klasse mit einer Basis Shape Klasse mit einem Draw Methode und erben dann diese Klasse zum Beispiel in Square und Circle Klassen. Sie könnten dann eine Methode wie folgt haben:

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

In diesem Fall ist es sinnvoll, die Draw Methode in den abgeleiteten Klassen, weil Sie so einfach anrufen können Draw wo immer du hast Shape Referenz und wissen, dass es richtig gezeichnet wird. Wenn diese Methode übergeben wird a Square dann wird ein Quadrat gezeichnet und wenn es passiert ist a Circle dann würde ein Kreis gezeichnet werden, aber die Methode muss dank Polymorphismus nicht wissen oder interessieren.

Wenn das, was du vorschlägst, möglich war, und Draw war ein Shared Methode, müssten Sie anrufen Square.Draw jedes Mal, wenn Sie ein Quadrat zeichnen wollten und Circle.Draw jedes Mal, wenn Sie einen Kreis zeichnen wollten. Der Hauptpunkt des Überschreibens ist, dass Sie in der Lage sein sollten, die Methode für eine Referenz des Basistyps aufzurufen und Funktionen zu erhalten, die im abgeleiteten Typ definiert sind. In Ihrem Szenario müssten Sie die Methode für den abgeleiteten Typ aufrufen, um die Funktionalität im abgeleiteten Typ zu definieren, sodass Sie keinen Vorteil erhalten. Du kannst nicht einfach anrufen Shape.Draw und etwas Nützliches passieren lassen. Abgesehen von allem anderen, welche abgeleitete Klasse würde es wählen?


4
2017-09-08 06:07



Sie versuchen, eine selbstbeschreibende Klasse zu erstellen.

Es gibt 3 Methoden:

  1. Abhängigkeitsinjektion: Verwenden Sie einen Rahmen wie Einheit (schwer, aber kann wirklich sein, was Sie wollen)
  2. Benutzerdefinierte Attribute: Zum Hinzufügen von Metadaten zur Klasse und zum anschließenden Scannen der Metadaten
  3. Selbstregistrierende Klassen (instanziieren und zerstören jede Unterklasse, um auf die motoverride-Eigenschaften zuzugreifen). Verwendet das Fabrikmuster.

Benutzerdefinierte Attribute:

Dies ist ein einfaches Beispiel, das ich gemacht habe:

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

Selbstregistrierende Klassen:

Dies ist eine wirklich gute Beschreibung mit Beispielen: http://www.jkfill.com/2010/12/29/self-registering-factories-in-c-sharp/

Von der 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
2018-03-25 01:46