我构建了一个我正在尝试编写的代码类型的简单示例:
Interface Breakable
Sub Break()
End Interface
Class Glass
Implements Breakable
Public Glassiness As Integer = 10
Sub Break() Implements Breakable.Break
Console.WriteLine("Smash!")
End Sub
End Class
Class Paper
Implements Breakable
Sub Break() Implements Breakable.Break
Console.WriteLine("Rip!")
End Sub
End Class
Sub Main()
Dim John As New Person
Dim BreakableObject As Breakable = New Glass
John.Mishandle(BreakableObject)
End Sub
在Person中,如果我写这个,VB将无法编译:
Class Person
Sub Mishandle(ByVal G As Glass)
G.Break()
Console.WriteLine(G.Glassiness)
End Sub
Sub Mishandle(ByVal P As Paper)
'Did not rip the paper.
End Sub
End Class
为了让它发挥作用,我需要这样做:
Class Person
Sub Mishandle(ByVal Breakable As Breakable)
If TypeOf Breakable Is Glass Then
Dim G As Glass = CType(Breakable, Glass)
G.Break()
Console.WriteLine(G.Glassiness)
ElseIf TypeOf Breakable Is Paper Then
'Nothing
End If
End Sub
End Class
如果我有很多实现Breakable的类,那就不那么优雅了。性能也是我正在处理的实际应用程序中的一个因素 - Mishandle()将被多次调用。我之前在使用Visitor模式的Java中做过这种事情,所以我很困惑为什么VB / C#告诉我:
Error 1 Overload resolution failed because no accessible 'Mishandle' can be called without a narrowing conversion:
'Public Sub Mishandle(P As Paper)': Argument matching parameter 'P' narrows from 'ConsoleApplication1.Module1.Breakable' to 'ConsoleApplication1.Module1.Paper'.
'Public Sub Mishandle(G As Glass)': Argument matching parameter 'G' narrows from 'ConsoleApplication1.Module1.Breakable' to 'ConsoleApplication1.Module1.Glass'.
是否有任何建议或我注定要使用TypeOf?非常感谢提前。
答案 0 :(得分:1)
基本上,事情可能会被打破,而不是任何人或任何事情。一种方法可能是反转界面并使用IFragile
:
Interface IFragile
Property Strength As Integer
Sub Break(power As Integer)
End Interface
Class Glass
Implements IFragile
Public Property Strength As Integer = 3 Implements IFragile.Strength
Sub Break(n As Integer) Implements IFragile.Break
If n > Strength Then
Console.WriteLine("Smash!")
End If
End Sub
End Class
Class Rock
Implements IFragile
Public Property Strength As Integer = 10 Implements IFragile.Strength
Sub Break(n As Integer) Implements IFragile.Break
If n > Strength Then
Console.WriteLine("Ka-POW!!")
End If
End Sub
End Class
现在,事情是可以破坏的,但基于另一个因素 - 力量与所施加的力量。
Class Person
Private Property Power As Integer = 7
' people cannot break Rocks, perhaps Elephants can
Sub Mishandle(B As IFragile)
B.Break(Power)
End Sub
End Class
测试:
Dim John As New Person
Dim G As IFragile = New Glass
John.Mishandle(G)
Dim R As IFragile = New Rock
John.Mishandle(R)
Glass, Rocks and People
并非全部相同,因此在创建时可能会分配或传递Strength
和Power
值。使用足够的变量优化接口,它应该变得相当灵活。
Dim Ziggy As New Person
Ziggy.Power = 1
Ziggy.Mishandle(G) ' should not break, ziggy is a weakling
同样地,给约翰一个SledgeHammer,他的力量增加到15,他可以轻松地打破岩石。对于更加严格和快速的规则 - “小猫不能破坏X,Y和Z”,我担心你可能不得不诉诸TypeOf
或GetType
。
如果您需要测试某个界面:
If BreakableObject.GetType.GetInterface("IBreakable") IsNot Nothing Then
Console.WriteLine("Fragile: This is IBreakable!")
End If
答案 1 :(得分:1)
决定调用哪个例程必须在某个地方进行,如果你使用重载,那么就会无形地为你做出TypeOf调用。所以,是的,你注定要使用它。接口没有代码,因此决定执行哪些代码只能通过找出您实际使用的类来实现。
如果您确定同时使用接口并避免显式使用TypeOf,则可以在接口中添加BaseObject函数:
Public Interface IBreakable
Sub Break()
Function BaseObject As Object
End Interface
然后在每个类中实现它:
Public Class Glass
Implements IBreakable
Public Function BaseObject() As Object Implements IBreakable.BaseObject
Return Me
End Function
并将其用于通话:
John.Mishandle(BreakableObject.BaseObject)
相当丑陋,但它可以保持你的重载... ...
答案 2 :(得分:0)
在试图澄清我的问题时,我发现了一个很好的解决方案:
Sub Main()
Dim John As New Person
Dim BreakableObject As Breakable = New Glass
Dim MysteryX As Object = BreakableObject
John.Mishandle(MysteryX)
End Sub
完美无缺。如果我像Plastic一样创建一个额外的类并实例化它,我会得到一个AmbiguousMatchException。
编辑:我刚刚发现性能明智,分支在TypeOf并以某种方式进行转换要好得多。上面的方法在最后一行调用ObjectLateGet,这非常昂贵。