Reputation: 4201
I want to write an interface that contains a method that has an argument of the same type like the implementing class.
Currently I'm using this:
Public Interface IContent(Of T)
Function ContentEquals(content As IContent(Of T)) As Boolean
End Interface
Public Class SpecificContent
Implements IContent(Of Specific)
Private m_Member As String
Public Function ContentEquals(content As IContent(Of Specific)) As Boolean Implements IContent(Of Specific).ContentEquals
' Actually I need to access content.m_Member here
' Of course this doesn't work
' since not every IContent(Of Specific) has m_Member
' just because SpecificContent does.
Return True
End Function
End Class
The problem is, that this interface definition requires the implementation of ContentEquals
to accept any object of any type implementing IContent(Of Specific)
, not just SpecificContent
what I actually want to define.
Is there a way to define a method in the interface I
that enforces a method that has an parameter of A
for A Implements I
and B
for B Impements I
, i. e. something like content As MyClass
?
Upvotes: 0
Views: 102
Reputation: 4201
I found out a proper way to achieve what I want. The solution is interface-inheritance and a second generic for the type you want as parameter type. I knew I had done something similar before, but it was in Java and I couldn't quite remember.
These are my interfaces:
Public Interface IContentFactory(Of T, S As IContent(Of T))
Function CreateFrom(obj As T) As IComparableContent(Of T, S)
End Interface
Public Interface IContent(Of T)
Sub ApplyTo(obj As T)
End Interface
Public Interface IComparableContent(Of T, S As IContent(Of T))
Inherits IContent(Of T)
Function ContentEquals(content As S) As Boolean
End Interface
In my code, I can use these interfaces for a generic content handling class:
Public Class ContentHistory(Of T, S As IContent(Of T))
Private m_Obj As T
Private m_Factory As IContentFactory(Of T, S)
Private m_History As Stack(Of IComparableContent(Of T, S))
Public Sub New(obj As T, factory As IContentFactory(Of T, S))
If obj Is Nothing Then Throw New ArgumentNullException("obj")
If factory Is Nothing Then Throw New ArgumentNullException("factory")
m_Obj = obj
m_Factory = factory
m_History = New Stack(Of IComparableContent(Of T, S))
End Sub
Public Sub Backup()
Dim currentContent = m_Factory.CreateFrom(m_Obj)
If m_History.Count = 0 OrElse Not m_History.Peek().ContentEquals(currentContent) Then
m_History.Push(currentContent)
End If
End Function
Private Sub Restore()
If m_History.Count > 0 Then
m_History.Pop().ApplyTo(m_Obj)
End If
End Function
End Class
Now I can implement specific classes for content-objects and their factories, like so:
Public Class SpecificContentFactory
Implements IContentFactory(Of Specific, SpecificContent)
Public Function CreateFrom(obj As Specific) As IComparableContent(Of Specific, SpecificContent) Implements IContentFactory(Of Specific, SpecificContent).CreateFrom
Return New SpecificContent(obj)
End Function
End Class
Public Class SpecificContent
Implements IComparableContent(Of Specific, SpecificContent)
Private ReadOnly m_Value As String
Friend Sub New(obj As Specific)
m_Value = obj.Value
End Sub
Public Sub ApplyTo(obj As Specific) Implements IContent(Of Specific).ApplyTo
obj.Value = m_Value
End Sub
Public Function ContentEquals(content As SpecificContent) As Boolean Implements IComparableContent(Of Specific, SpecificContent).ContentEquals
Return (content.m_Value = m_Value)
End Function
End Class
To setup this content handler, all I have to do is
Dim obj = New Specific()
Dim history = New ContentHistory(Of Specific, SpecificContent)(obj, New SpecificContentFactory())
and I can use it like
obj.Value = "OldValue"
history.Backup
obj.Value = "OldValue"
history.Backup ' Nothing happens
obj.Value = "NewValue"
history.Backup
obj.Value = "EvenNewerValue"
Dim value = obj.Value ' "EvenNewerValue"
history.Restore
value = obj.Value ' "NewValue"
history.Restore
value = obj.Value ' "OldValue"
history.Restore ' Nothing happens
value = obj.Value ' "OldValue"
As long as I provide the SpecificContent
and SpecificContentFactory
implementations, I can use the ContentHistory(Of Specific, SpecificContent)
for any type as Specific
that I like.
Upvotes: 0
Reputation: 78164
No, there isn't. And frankly, it's a good thing.
Think about it - how would you be able to use such interface? The point of an interface is that you can call certain method regardless of the type of the object that actually implements the interface. If the interface contained a method bound to its implementor's type, in variable of which type would you store that interface? And if you could store it in a variable, how would you pass it to a method that is not aware about the impelementor, only knowing about the interface? How would that method be able to call the interface, what would it pass as a parameter?
For this kind of equality testing you're supposed to override the Object.Equals
method, or introduce another overload of Object.Equals
that explicitly accepts your own type. You can still use an interface, too, but the parameter will have to be of type Object
, just like it is with Object.Equals
.
Upvotes: 2