我最近为我实现的一些自定义用户控件添加了一个界面。界面非常基础。它有一种支持链接的方法:
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())
someCustomControl
是MyCustomControl
,它实现IMyInterface(Of MyCustomControl)
而不是IMyInterface(Of WebControl)
。
我在第二行(我尝试添加someCustomControl
)时收到此错误:
Option Strict On禁止从“MyCustomControl”到“IMyInterface(Of WebControl)”的隐式转换。
有没有办法解决这个错误?我很接近它的工作,但我不太了解泛型超越这一点。
答案 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
当你必须在接口定义中指定类型时,它会消除接口的功能(不必了解实现)。