ConcurrentQueue(Of T)的元素不能加宽

时间:2016-05-27 15:45:41

标签: .net vb.net generics casting type-parameter

假设我有这个Sub:

Sub Process(InputQueue as ConcurrentQueue(Of Object))
    .... some codes ....
End Sub

现在我有了这个

Class JobDesc
    .... some codes ....
End Class

Dim MainJobQueue As New ConcurrentQueue(Of JobDesc)

如果我尝试将MainJobQueue作为参数传递给Process(),为什么VB.Net会抱怨?

即,这样做:

Process(MainJobQueue)

将导致以下错误消息:

  

'ConcurrentQueue(Of JobDesc)'类型的值无法转换为'ConcurrentQueue(Of Object)'。

JobDesc不是Object的子类,因此将JobDesc投射到Object会是'扩大'而不是缩小?

3 个答案:

答案 0 :(得分:2)

您可以创建这样的通用方法(即如果我仍然记得vb.net)

Sub Process(of T as Object)(InputQueue as ConcurrentQueue(Of T))

答案 1 :(得分:1)

  

JobDesc不是Object的子类,因此将JobDesc转换为Object将是一个扩展'而不是缩小?

是的,但问题是ConcurrentQueue可变集合。

因此,它的类型参数不仅定义了可以从中获取的对象,还定义了它将接受的 new 元素。

如果您可以直接将其投射到ConcurrentQueue(of Object),则可以执行此操作:

Sub Process(InputQueue as ConcurrentQueue(Of Object))
    InputQueue.Enqueue("Whoops, this is not a JobDesc!")
End Sub

Process(MainQueue)

Dim getLatestJob = MainQueue.Dequeue() // WTF, why did it give me a String?

(好吧,理论上。如果你真的设法编译了这个,那么程序会因InvalidCastException而崩溃。)

现在,如果您计划将任何非JobDesc元素添加到队列中,那么您有几个选项。

  • 您可以通过将Process编写为通用方法来强制执行类型约束。

    Sub Process(Of SomeType)(InputQueue as ConcurrentQueue(Of SomeType))
         InputQueue.Enqueue("Whoops, this is not a SomeType!")
         // will not compile, input is not SomeType
    End Sub
    
  • 或者,您可以将ConcurrentQueue转换为基类或类似IEnumerable(Of T)的接口,允许向集合添加新元素,因此可以安全地转换为更广泛的类型,如Object(技术术语:covariant)。

     Dim MainQueueReadOnly As IEnumerable(Of JobDesc) = MainQueue
    
     Sub Process(InputQueue as IEnumerable(Of Object))
         InputQueue.Enqueue(anything) 
         // will not compile as IEnumerable doesn't have an .Enqueue method
     End Sub
    

但是,如果您 ,打算在队列中添加一些Object,那么您唯一的选择就是创建一个新的,不同的集合InputQueue,将接受除JobDesc以外的其他类型的元素。

Dim newQueue As New ConcurrentQueue(Of Object)(MainJobQueue)

答案 2 :(得分:0)

这并不像您期望的那样工作,因为IEnumerable<Base>不是协变的。来自CreateModelMixin

  

协方差可让您使用比最初指定更多的派生类型。

     

您可以将IEnumerable(IEnumerable(Of Derived)在Visual Basic中)的实例分配给类型为IEnumerable(Of Object)的变量。

如果您将方法更改为接受IReadOnlyList(Of Object)Sub Process(InputQueue As IEnumerable(Of Object)) '....some codes .... End Sub ,那么它的编译就可以了,因为这些接口是协变的:

requirements:
Django==1.8.8
kombu==3.0.35
celery==3.1.23
django-celery==3.1.17