6

I recently added an interface to some custom user controls I have implemented. The interface is pretty basic. It has one method that supports chaining:

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

The implementations are also pretty basic:

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

Everything works fine up to this point. The issues arise when I attempt to loop over a collection of controls that all implement the IMyInterface interface, like so:

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

myList.Add(someCustomControl)

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

someCustomControl is a MyCustomControl which implements IMyInterface(Of MyCustomControl) instead of IMyInterface(Of WebControl).

I am getting this error on the second line (where I try to add someCustomControl):

Option Strict On disallows implicit conversions from 'MyCustomControl' to 'IMyInterface(Of WebControl)'.

Is there any way to get around this error? I am close to having it working but I do not know enough about generics to get beyond this point.

4

3 回答 3

4

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

公共接口IMyInterface( Out T As WebControl)
    函数 DoSomething() 作为 T
端接口

当您使用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 上的更多信息:

于 2013-06-14T03:28:04.783 回答
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 />")

结果是,CssClasssomeCustomControl 和 someCustomControl2 的属性都设置为各自的值。

这说明接口函数DoSomething调用成功,实例发生变化。

于 2013-06-14T04:34:05.340 回答
0

您需要在添加对象之前对其进行转换:

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

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

Public Interface IMyInterface
    Function DoSomething() As IMyInterface
End Interface

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

于 2013-06-10T19:27:09.587 回答