存储实现多个接口并派生自某个基础(.net)的对象

发布于 2024-10-06 05:34:13 字数 1670 浏览 0 评论 0原文

在 .net 中,可以使用泛型,以便函数可以接受支持一个或多个接口并从基类型派生的参数,即使不存在可派生所有有效参数类型的任何单一类型。例如,可以说:

Sub Foo(Of T As {IInterface1, IInterface2, SomeBaseType})(Param as T)

并允许传递同时实现 IInterface1 和 IInterface2 的 SomeBaseType 的任何派生类。即使 SomeBaseType 不支持 Interface1 和 Interface2,并且实现这些接口的类不共享任何也实现它们的共同祖先,这也将起作用。

如果函数退出后不需要将参数保留在任何地方,这会非常方便。不幸的是,我无法找到一种方法来持久保存传入的参数,以便以后可以将其传递给类似的函数,除非使用反射。有什么好的方法吗?

我能想到的最接近的是定义一个接口 INest (也许不是最好的名字——任何人都可以改进它吗?)因此:

Interface INest(Of Out T)
    Function Nest() As T
End Interface

对于任何将与其他接口或基类结合使用的接口“constraint”,定义一个通用版本,如下所示

Interface IFun1
    ' Any members of the interface go here, e.g. ...'
    Sub DoFun1()
End Interface

Interface IFun1(Of Out T)
    ' This one does nothing but inherit'
    Inherits IFun1, INest(Of T)
End Interface

支持多个接口的类应该将自身声明为实现通用接口,并将其自身作为类型参数。

Class test123a
    Inherits sampleBase
    Implements IFun1(Of test123a), IFun2(Of test123a), IFun3(Of test123a)
End Class

如果完成了这一点,就可以定义一个支持多个约束的函数参数或类变量:

Dim SomeField as IFun1(Of IFun2(Of IFun3(Of sampleBase)))

然后将其分配给它任何从sampleBase派生的类,该类实现了这些接口。 SomeField 将实现 IFun1; SomeField.Nest 将实现 IFun2; SomeField.Nest.Nest 将实现 IFun3。请注意,除了从 INest(Of T) 继承的通用接口之外,不要求 IFun1、IFun2、IFun3 或 sampleBase 共享任何公共派生。还要注意,无论一个类实现多少个 INest 派生接口,它只需要定义一个 INest(Of T).Nest 的实现。

不太漂亮,但它有两个好处:(1)任何实际上实现必要接口的具体类都可以直接分配给上面声明的字段,而无需进行类型转换; (2) 虽然以不同顺序链接类型的字段不兼容分配,但它们可以相互类型转换。

有没有更好的方法来存储某些东西,使其“已知”支持多个接口并从某种基类型派生?鉴于人们可以以类型安全的方式编写这样的代码,如果编译器提供一点帮助,.net 2.0 CLR 似乎可以很好地支持这样的事情。不过,我不知道目前的编译器有什么特别好的方法。

In .net, it's possible to use generics so that a function can accept arguments which support one or more interfaces and derive from a base type, even if there does not exist any single type from which all valid argument types derive. For example, one could say:

Sub Foo(Of T As {IInterface1, IInterface2, SomeBaseType})(Param as T)

and be allowed to pass any derivative of SomeBaseType which implements both IInterface1 and IInterface2. This will work even if SomeBaseType does not support Interface1 and Interface2, and classes which do implement those interfaces don't share any common ancestor that also implements them.

This can be very convenient if one won't need to keep the parameter anywhere after the function has exited. Unfortunately, I can't figure out a way to persist the passed-in parameter in such a way that it can later be passed to a similar function, except perhaps by using Reflection. Is there any nice way of doing that?

The closest I've been able to come up with is to define an interface INest (perhaps not the best name--can anyone improve it?) thus:

Interface INest(Of Out T)
    Function Nest() As T
End Interface

And for any interface that will be used in combination with others or with base-class "constraint", define a generic version as illustrated below

Interface IFun1
    ' Any members of the interface go here, e.g. ...'
    Sub DoFun1()
End Interface

Interface IFun1(Of Out T)
    ' This one does nothing but inherit'
    Inherits IFun1, INest(Of T)
End Interface

A class which will support multiple interfaces should declare itself as implementing the generic ones, with itself as the type argument.

Class test123a
    Inherits sampleBase
    Implements IFun1(Of test123a), IFun2(Of test123a), IFun3(Of test123a)
End Class

If that is done, one can define a function argument or class variable that supports multiple constraints thusly:

Dim SomeField as IFun1(Of IFun2(Of IFun3(Of sampleBase)))

and then assign to it any class derived from sampleBase, which implements those interfaces. SomeField will implement IFun1; SomeField.Nest will implement IFun2; SomeField.Nest.Nest will implement IFun3. Note that there's no requirement that IFun1, IFun2, IFun3, or sampleBase share any common derivation other than the generic interfaces inheriting from INest(Of T). Note also that, no matter how many INest-derived interfaces a class implements, it only needs to define one implementation of INest(Of T).Nest.

Not exactly beautiful, but there are two nice things about it: (1) any concrete class which in fact implements the necessary interfaces can be assigned directly to a field declared as above, without a typecast; (2) while fields which chain the types in a different order are not assignment compatible, they may be typecast to each other.

Is there any better way to store something in such a way that it's "known" to support multiple interfaces and derive from a certain base type? Given that one can write such code in a type-safe manner, it would seem like the .net 2.0 CLR could probably support such a thing quite nicely if compilers offered a little assistance. I'm unaware of any particularly nice approach with present compilers, though.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

海未深 2024-10-13 05:34:13

我能想到的最好的方法是制作一个抽象存储和该存储的通用实现。例如(请原谅我的 VB.NET):

MustInherit Class Storage
    Public MustOverride Sub DoSomething()
End Class

Class Storage(Of T As {IInterface1, IInterface2, SomeBaseType})
    Inherits Storage

    Public Overrides Sub DoSomething()
        ' do something with Value.
    End Sub

    Public Value As T
End Class

和用法

Dim S As Storage

Sub Foo(Of T As {IInterface1, IInterface2, SomeBaseType})(ByVal Param As T)
    S = New Storage(Of T) With {.Value = Param}
End Sub

Sub UseS()
    S.DoSomething();
End Sub

更新: 好的,因为我们可能无法提前识别所有操作:

MustInherit Class Storage
    MustOverride ReadOnly Property SomeBaseType As SomeBaseType
    MustOverride ReadOnly Property IInterface1 As IInterface1
    MustOverride ReadOnly Property IInterface2 As IInterface2
End Class

Class Storage(Of T As {IInterface1, IInterface2, SomeBaseType})
    Inherits Storage

    Public Value As T

    Public Overrides ReadOnly Property IInterface1 As IInterface1
        Get
            Return Value
        End Get
    End Property

    Public Overrides ReadOnly Property IInterface2 As IInterface2
        Get
            Return Value
        End Get
    End Property

    Public Overrides ReadOnly Property SomeBaseType As SomeBaseType
        Get
            Return Value
        End Get
    End Property
End Class

The best way I can think of is to make an abstract storage and generic implementation of this storage. For example (excuse my VB.NET):

MustInherit Class Storage
    Public MustOverride Sub DoSomething()
End Class

Class Storage(Of T As {IInterface1, IInterface2, SomeBaseType})
    Inherits Storage

    Public Overrides Sub DoSomething()
        ' do something with Value.
    End Sub

    Public Value As T
End Class

And usage

Dim S As Storage

Sub Foo(Of T As {IInterface1, IInterface2, SomeBaseType})(ByVal Param As T)
    S = New Storage(Of T) With {.Value = Param}
End Sub

Sub UseS()
    S.DoSomething();
End Sub

Update: Ok, because we may not be able identify in advance all of the actions:

MustInherit Class Storage
    MustOverride ReadOnly Property SomeBaseType As SomeBaseType
    MustOverride ReadOnly Property IInterface1 As IInterface1
    MustOverride ReadOnly Property IInterface2 As IInterface2
End Class

Class Storage(Of T As {IInterface1, IInterface2, SomeBaseType})
    Inherits Storage

    Public Value As T

    Public Overrides ReadOnly Property IInterface1 As IInterface1
        Get
            Return Value
        End Get
    End Property

    Public Overrides ReadOnly Property IInterface2 As IInterface2
        Get
            Return Value
        End Get
    End Property

    Public Overrides ReadOnly Property SomeBaseType As SomeBaseType
        Get
            Return Value
        End Get
    End Property
End Class
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文