那么为什么不允许Shared
MustOverride
/ Overridable
成员呢?有些人认为覆盖与继承有关,这对于Shared
成员来说没有意义,因为没有涉及实例化。这是我需要它的一个例子:
我的基类DrawingObject
定义了一个名为Shared
的{{1}}成员,每个子类必须实现该成员才能返回唯一的标识字符串,该字符串对于每种子类型都不同,但是相同对于一个子类型的所有实例。现在,这要求我将TypeName
属性定义为TypeName
和Shared
。或者有更好的方法吗?
基础课程
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
。
答案 0 :(得分:4)
重写的重点是促进多态性。传递一个对象,它的行为方式取决于对象的类型而不是引用的类型。如果你正在调用Shared
成员,那么你就是在一个类型而不是一个对象上调用它们,所以多态不适用,所以覆盖提供没有优势。
在您的情况下,如果您想在不知道该对象在运行时的类型的情况下获取对象的TypeName
,那么覆盖该属性将是有意义的。无论您身在何处,都可以获得该属性,并且您将获得该对象类型的名称。使用共享成员,您将获得特定类型的属性,因此您只需获取该类型的属性。
请求的示例:
让我们说你的形状知道如何在屏幕上绘制自己。您可以从基础Shape
类开始,基类Shape
类使用Draw
方法,然后继承该类,例如Square
和Circle
类。然后你可以有这样的方法:
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种方法:
自定义属性:
这是我做的一个简单例子:
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");
}
}
}
}