vb.net специализированные / перегруженные дженерики - PullRequest
2 голосов
/ 26 января 2012

Я склонен ненавидеть повторения в коде, поэтому, когда я сталкиваюсь с проблемой, где единственными отличиями являются типы, я склонен использовать обобщенные типы. Исходя из 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 против C ++, AFAIK, C ++ будет проверять типы во время компиляции и только по тем типам, которые отправляются на решение. Тем не менее, в vb.net я получаю сообщение об ошибке, что тип T не может быть преобразован в String или Integer

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), но ограничения должны быть классами Inheritable, поэтому нельзя использовать ни String, ни 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. Что, я думаю, имеет смысл в свете предыдущего, не может конвертировать ошибки. Я сталкивался с этой проблемой раньше, когда существуют неуниверсальные перегрузки универсальной подпрограммы, тогда я не мог найти решение и не могу найти решение сейчас.

Есть ли что-то, чего мне не хватает, что сделало бы возможным этот тип перегрузки?

Редактировать: полный рабочий пример

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

1 Ответ

1 голос
/ 27 января 2012

От Различия между шаблонами C ++ и универсальными C # (то же самое относится и к VB .NET):

C ++ допускает код, который может быть недопустимым для всех параметров типа в шаблон, который затем проверяется на конкретный тип, используемый в качестве типа параметр. C # требует, чтобы код в классе был написан таким образом что он будет работать с любым типом, который удовлетворяет ограничениям. За Например, в C ++ можно написать функцию, которая использует арифметические операторы + и - на объектах типа параметр, который выдаст ошибку во время создания шаблона с типом, который не поддерживает эти операторы. C # запрещает это; допускаются только языковые конструкции, которые могут быть выведены из ограничений.

Я не могу решить вашу проблему с помощью .NET Generics. Но вы можете избежать повторения логики, используя лямбды и замыкания, которые я также считаю более естественным способом сделать это в .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 
...