泛型,接口和转换问题

时间:2013-06-10 19:14:59

标签: vb.net generics interface user-controls

我最近为我实现的一些自定义用户控件添加了一个界面。界面非常基础。它有一种支持链接的方法:

Public Interface IMyInterface(Of T As WebControl)
    Function DoSomething() As T
End Interface

这些实现也非常基础:

Public Class MyCustomControl
    Inherits CompositeControl
    Implements IMyInterface(Of MyCustomControl)

Public Function DoSomething() As MyCustomControl _
    Implements IMyInterface(Of MyCustomControl).DoSomething
    ' do stuff

    Return Me
End Class

到目前为止,一切正常。当我尝试遍历所有实现IMyInterface接口的控件集合时会出现问题,如下所示:

Dim myList = New List(Of IMyInterface(Of WebControl))

myList.Add(someCustomControl)

myList.ForEach(Sub(i) i.DoSomething())

someCustomControlMyCustomControl,它实现IMyInterface(Of MyCustomControl)而不是IMyInterface(Of WebControl)

我在第二行(我尝试添加someCustomControl)时收到此错误:

  

Option Strict On禁止从“MyCustomControl”到“IMyInterface(Of WebControl)”的隐式转换。

有没有办法解决这个错误?我很接近它的工作,但我不太了解泛型超越这一点。

3 个答案:

答案 0 :(得分:4)

协方差是VS 2010中引入的一种语言功能,可以解决您的问题。您需要定义通用,以使T类型前面有Out个关键字:

Public Interface IMyInterface(Of Out T As WebControl)
    Function DoSomething() As T
End Interface

使用Out关键字时,您正在使用协方差。它允许使用更派生类型的泛型来代替基类型的泛型。因此,在您的情况下,它会在代码通常需要IMyInterface(Of MyCustomControl))的位置允许IMyInterface(Of WebControl))个对象,例如for循环。

请注意,协方差有一个限制。协变类型T只能用作函数返回值,而不能用作函数(或子)的参数。例如,如果DoSomething中的IMyInterface签名看起来像这样,编译器就会抱怨:

' Here the type T is used as an input param - compiler error
Sub DoSomething(ByVal sampleArg As T)

鉴于您的链接情况,我不认为上述限制是一个问题。

MSDN上的更多信息:

答案 1 :(得分:1)

我不知道你的函数DoSomething做了什么,但我尝试在那里分配实例的CssClass用于测试目的。

按如下方式声明接口:

Public Interface IMyInterface(Of Out T As WebControl)
    Function DoSomething() As T
End Interface

请注意 Out T 参数。

创建2个实现界面的控件:

Public Class MyCustomControl1
    Inherits CompositeControl
    Implements IMyInterface(Of MyCustomControl1)

    Public Function DoSomething() As MyCustomControl1 Implements IMyInterface(Of MyCustomControl1).DoSomething
        ' do stuff
        Me.CssClass = "XXX"
        Return Me
    End Function

End Class

Public Class MyCustomControl2
    Inherits CompositeControl
    Implements IMyInterface(Of MyCustomControl2)

    Public Function DoSomething() As MyCustomControl2 Implements IMyInterface(Of MyCustomControl2).DoSomething
        ' do stuff
        Me.CssClass = "YYY"
        Return Me
    End Function

End Class

在测试页的PageLoad事件中:

Dim someCustomControl As New MyCustomControl1
Dim someCustomControl2 As New MyCustomControl2

Dim myList = New List(Of IMyInterface(Of WebControl))

myList.Add(someCustomControl)
myList.Add(someCustomControl2)

myList.ForEach(Sub(i) Literal1.Text &= i.DoSomething.CssClass & "<br />")

结果是,someCustomControl&amp;的CssClass属性。 someCustomControl2设置为相应的值。

这表明已成功调用接口函数DoSomething并更改了实例。

答案 2 :(得分:0)

您需要在添加对象之前强制转换对象:

myList.Add(CType(someCustomControl, IMyInterface(Of WebControl)))

您可能还想要使接口不是通用的,而“DoWork”方法返回类型作为接口本身。

Public Interface IMyInterface
    Function DoSomething() As IMyInterface
End Interface

当你必须在接口定义中指定类型时,它会消除接口的功能(不必了解实现)。