В .net можно использовать обобщенные значения, чтобы функция могла принимать аргументы, которые поддерживают один или несколько интерфейсов, и являются производными от базового типа, даже если не существует какого-либо единственного типа, из которого происходят все действительные типы аргументов.Например, можно сказать:
Sub Foo(Of T As {IInterface1, IInterface2, SomeBaseType})(Param as T)
и ему разрешено передавать любую производную SomeBaseType, которая реализует как IInterface1, так и IInterface2.Это будет работать, даже если SomeBaseType не поддерживает Interface1 и Interface2, а классы, которые реализуют эти интерфейсы, не имеют общего предка, который также реализует их.
Это может быть очень удобно, если не нужнооставьте параметр в любом месте после выхода из функции.К сожалению, я не могу найти способ сохранить переданный параметр таким образом, чтобы впоследствии его можно было передать в аналогичную функцию, за исключением, возможно, использования Reflection.Есть ли какой-нибудь хороший способ сделать это?
Самое близкое, что я смог придумать, - это определить интерфейс INest (возможно, не лучшее имя - кто-нибудь может его улучшить?), Таким образом:
Interface INest(Of Out T)
Function Nest() As T
End Interface
И для любого интерфейса, который будет использоваться в сочетании с другими или с «ограничением» базового класса, определите универсальную версию, как показано ниже
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.Обратите внимание, что не требуется, чтобы IFun1, IFun2, IFun3 или sampleBase совместно использовали какие-либо общие производные, кроме универсальных интерфейсов, наследуемых от INest (Of T).Также обратите внимание, что независимо от того, сколько производных от INest интерфейсов реализует класс, ему нужно только определить одну реализацию INest (Of T) .Nest.
Не совсем красиво, но в этом есть две приятные вещи: (1) любой конкретный класс, который фактически реализует необходимые интерфейсы, может быть назначен непосредственно полю, объявленному, как указано выше, без приведения типа;(2) хотя поля, объединяющие типы в другом порядке, несовместимы по присваиванию, они могут быть преобразованы по типу друг в друга.
Есть ли лучший способ хранить что-либо таким образом, чтобы это «стало известно»поддержка нескольких интерфейсов и наследование от определенного базового типа?Учитывая, что можно написать такой код безопасным для типов способом, может показаться, что .net 2.0 CLR, вероятно, вполне может поддерживать такую вещь, если компиляторы предложат небольшую помощь.Я не знаю ни одного особенно приятного подхода с существующими компиляторами.