我倾向于厌恶代码中的重复,所以当我遇到唯一不同的是类型的问题时,我倾向于使用泛型。来自 C++ 背景,我发现 vb.net 的版本相当令人沮丧,我知道 C++ 有模板特化,我猜 vb.net 没有 所以我有一组例程,无论传递的类型如何,它们都执行完全相同的代码。
像这样
Public Sub decision(Of T)(ByVal a As T, ByVal b As Integer)
If b > 10 then
gt(a)
Else
lt(a)
End If
End Sub
我只将两种类型传递给例程,字符串和整数,这些例程对字符串的处理与对整数的处理不同。
Public Sub gt(ByVal a As String)
Public Sub gt(ByVal a As Integer)
Public Sub lt(ByVal a As String)
Public Sub lt(ByVal a As Integer)
这就是我对 vb.net vs C++ 感到沮丧的地方,据我所知,C++ 会在编译时检查类型,并且只针对发送给决策的类型进行检查。但是,在 vb.net 中我得到一个错误,类型 T 无法转换为字符串或整数
Error 3 Overload resolution failed because no accessible 'gt' can be called with these arguments:
'Public Sub gt(a As String)': Value of type 'T' cannot be converted to 'String'.
'Public Sub gt(a As Integer)': Value of type 'T' cannot be converted to 'Integer'.
我尝试了约束 Public Sub decision(Of T As {String, Integer})(ByVal a As T, ByVal b As Integer)
但约束必须是可继承的类,因此既不是字符串也不是整数可以使用。
我的下一个解决方案是添加 gt
和 lt
的通用版本:
Public Sub lt(Of T)(ByVal a As T)
Debug.Fail("Not Implemented")
End Sub
Public Sub lt(Of T)(ByVal a As T)
Debug.Fail("Not Implemented")
End Sub
嘿!没有更多的编译错误,但是唯一被调用的例程是 gt
和 lt
的通用版本。鉴于之前的 cannot convert 错误,我想这是有道理的。我以前遇到过这个问题,那里有泛型例程的非泛型重载,当时我找不到解决方案,现在也找不到解决方案。
是否有什么我遗漏的东西会使这种类型的重载成为可能?
编辑:一个完整的工作示例
Module Module1
Sub Main()
decision(1, 5)
decision(1, 10)
decision("hello world", 5)
decision("hello world", 10)
End Sub
Public Sub decision(Of T)(ByVal a As T, ByVal b As Integer)
If b > 10 Then
gt(a)
Else
lt(a)
End If
End Sub
Public Sub gt(ByVal a As String)
Debug.WriteLine(" gt string: " + a)
End Sub
Public Sub gt(ByVal a As Integer)
Debug.WriteLine(" gt integer: " + a.ToString)
End Sub
Public Sub lt(ByVal a As String)
Debug.WriteLine(" lt string: " + a)
End Sub
Public Sub lt(ByVal a As Integer)
Debug.WriteLine(" lt integer: " + a.ToString)
End Sub
#If False Then
Public Sub gt(Of T)(ByVal a As T)
Debug.Fail("Not implemented")
End Sub
Public Sub lt(Of T)(ByVal a As T)
Debug.Fail("Not implemented")
End Sub
#End If
End Module
最佳答案
来自 Differences Between C++ Templates and C# Generics (同样适用于 VB .NET):
C++ allows code that might not be valid for all type parameters in the template, which is then checked for the specific type used as the type parameter. C# requires code in a class to be written in such a way that it will work with any type that satisfies the constraints. For example, in C++ it is possible to write a function that uses the arithmetic operators + and - on objects of the type parameter, which will produce an error at the time of instantiation of the template with a type that does not support these operators. C# disallows this; the only language constructs allowed are those that can be deduced from the constraints.
我无法使用 .NET 泛型解决您的问题。但是您可以通过使用 lambda 和闭包来避免重复逻辑,我也认为这是在 .NET 中执行此操作的更自然的方法:
Public Sub Decision(ByVal a As String, ByVal b As Integer)
Decision(b, Sub() gt(a), Sub() lt(a))
End Sub
Public Sub Decision(ByVal a As Integer, ByVal b As Integer)
Decision(b, Sub() gt(a), Sub() lt(a))
End Sub
Private Sub decision(ByVal b As Integer, ByVal gt As Action, ByVal lt As Action)
If b > 10 Then
gt()
Else
lt()
End If
End Sub
Public Sub gt(ByVal a As String)
Debug.WriteLine(" gt string: " + a)
End Sub
Public Sub gt(ByVal a As Integer)
Debug.WriteLine(" gt integer: " + a.ToString)
End Sub
Public Sub lt(ByVal a As String)
Debug.WriteLine(" lt string: " + a)
End Sub
Public Sub lt(ByVal a As Integer)
Debug.WriteLine(" lt integer: " + a.ToString)
End Sub
关于vb.net 专用/重载泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9023915/