Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
788 views
in Technique[技术] by (71.8m points)

vb.net - Storing an object that implements multiple interfaces and derives from a certain base (.net)

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...