声明共享MustOverride

时间:2015-09-08 04:38:58

标签: vb.net oop override shared

那么为什么不允许Shared MustOverride / Overridable成员呢?有些人认为覆盖与继承有关,这对于Shared成员来说没有意义,因为没有涉及实例化。这是我需要它的一个例子:

我的基类DrawingObject定义了一个名为Shared的{​​{1}}成员,每个子类必须实现该成员才能返回唯一的标识字符串,该字符串对于每种子类型都不同,但是相同对于一个子类型的所有实例。现在,这要求我将TypeName属性定义为TypeNameShared。或者有更好的方法吗?

基础课程

Overridable

儿童课

Public MustInherit Class DrawingObject
    Public MustOverride ReadOnly Property TypeName As String
End 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 应为TypeName,因为它返回Shared

2 个答案:

答案 0 :(得分:4)

重写的重点是促进多态性。传递一个对象,它的行为方式取决于对象的类型而不是引用的类型。如果你正在调用Shared成员,那么你就是在一个类型而不是一个对象上调用它们,所以多态不适用,所以覆盖提供没有优势。

在您的情况下,如果您想在不知道该对象在运行时的类型的情况下获取对象的TypeName,那么覆盖该属性将是有意义的。无论您身在何处,都可以获得该属性,并且您将获得该对象类型的名称。使用共享成员,您将获得特定类型的属性,因此您只需获取该类型的属性。

请求的示例:

让我们说你的形状知道如何在屏幕上绘制自己。您可以从基础Shape类开始,基类Shape类使用Draw方法,然后继承该类,例如SquareCircle类。然后你可以有这样的方法:

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

在这种情况下,覆盖派生类中的Draw方法是有意义的,因为这样做只允许您在Draw引用的任何地方调用Shape并知道它将会正确绘制。如果通过Square传递该方法,则会绘制一个正方形,如果传递了Circle,则会绘制一个圆,但该方法不必知道或关心,谢谢多态性。

如果你的建议是可行的,并且Draw是一种Shared方法,则每次想要绘制正方形时都需要调用Square.Draw并{{1}每次你想画一个圆圈。覆盖的重点是,您应该能够在基类型的引用上调用该方法,并获得在派生类型中定义的功能。在您的方案中,您必须在派生类型上调用方法以获取派生类型中定义的功能,因此您没有任何优势。你不能只是打电话给Circle.Draw并发生任何有用的事情。除了其他任何东西,它会选择哪个派生类?

答案 1 :(得分:0)

您正在尝试创建一个自描述类。

有3种方法:

  1. 依赖注入:使用统一的框架(沉重但可能真的是你想要的)
  2. 自定义属性:向类中添加元数据,然后扫描元数据
  3. 自注册类(实例化并销毁每个子类以访问mustoverride属性)。使用工厂模式。
  4. 自定义属性:

    这是我做的一个简单例子:

    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
    

    自行注册课程:

    这是一个非常好的写作示例: http://www.jkfill.com/2010/12/29/self-registering-factories-in-c-sharp/

    来自网站:

    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");
                }
            }
        }
    }