自引用泛型和继承

时间:2014-04-01 04:29:11

标签: vb.net generics

我有一个AnimalQueue类,它是一个动物队列。每个队列只存储某种类型的Animal,我想确保只添加与队列类型匹配的Animal:

Public Class AnimalQueue(Of T As Animal)
    Public Sub Add(pA As T)
    End Sub
End Class

当处理队列中的Animal时,我想将处理它的队列传递给Animal,以防Animal想要将另一个Animal添加到同一队列:

Public MustInherit Class Animal
    Public MustOverride Sub Process(Of T As Animal)(pAQ As AnimalQueue(Of T))
End Class

问题是,当我添加一个具体的类时,我在调用Add:

时遇到编译错误
Public Class Horse
    Inherits Animal

    Public Overrides Sub Process(Of T As Animal)(pAQ As AnimalQueue(Of T))
        pAQ.Add(New Horse())
    End Sub
End Class

它说马不能转换为T,但约束说T是动物,马是动物......

1 个答案:

答案 0 :(得分:1)

问题是T可能是源自动物的任何类。假设以下类层次结构:

Horse -> Animal
Dog -> Animal

在您的代码中,T的通用参数Process被限制为任何动物。因此,即使您在Horse类上实现它,以下调用也将完全有效:

Dim dogQ As New AnimalQueue(Of Dog)()
Dim h As New Horse()
h.Process(Of Dog)(dogQ)

在这种情况下,您Process的实施会尝试将Horse添加到Dogs的队列中。由于Horse不是来自Dog,因此您无法执行此操作。

我假设您要创建一个方法,以便Process Horse方法仅接受Horses的队列和Process Dog方法}只接受Dogs的队列。

有几种方法可以实现这一目标:

  1. 不要在基类级别创建通用Process方法,而只在子级别创建Process个方法(例如HorsePublic Sub Process(horseQ As AnimalQueue(Of Horse)) )。
  2. 使用New约束并在Animal级别上实施该方法。在你的评论中,你提到你的动物需要构造函数参数,所以这不是一个选项。
  3. 如果要拥有定义泛型方法的基类,可以创建以下结构:

  4. Public Class AnimalQueue(Of T As Animal)
        Public Sub Add(animal As T)
            ' ...
        End Sub
    End Class
    
    Public MustInherit Class Animal
    
    End Class
    
    Public MustInherit Class ProcessableAnimal(Of T As Animal)
        Inherits Animal
    
        Public MustOverride Sub Process(q As AnimalQueue(Of T))
    
    End Class
    
    Public Class Horse
        Inherits ProcessableAnimal(Of Horse)
    
        Public Overrides Sub Process(q As AnimalQueue(Of Horse))
            q.Add(New Horse())
        End Sub
    End Class
    
    Public Class Dog
        Inherits ProcessableAnimal(Of Dog)
    
        Public Overrides Sub Process(q As AnimalQueue(Of Dog))
            q.Add(New Dog())
        End Sub
    End Class
    

    在这种方法中,有一个新的继承级别。但重大变化是您在类级别设置泛型类型参数。因此,在从ProcessableAninmal派生时做出决定,而不是留给Process的调用者。

    Dim h As New Horse()
    Dim hQ As New AnimalQueue(Of Horse)()
    Dim dQ As New AnimalQueue(Of Dog)()
    h.Process(hQ) ' Valid
    h.Process(dQ) ' NOT VALID ANYMORE