lundi 20 mars 2017

How Do I cast between 2 types that implement the same interface

I have a overlapping data objects that need to be given to at least one, possibly more, of several calculation methods to produce a common data object.

I think this is best solved by implementing both covarriance contravariance but I haven't been able to wrap my head around how what that would look like so I am open to other suggestions. In reality Animal/IAnimal and Noise have a lot of data properties so I'd like to avoid mapping them in constructors as much as possible.

Public Class Noise
    Public Property Sound() As String
    Public Sub Listen()
        Console.WriteLine(sound)
    End Sub 
End Class

Public Interface IAnimal
    Function Speak() As Noise
    Property Name() As String
End Interface

Public Class Dog
    Implements IAnimal
    Public Function Speak() As Noise Implements IAnimal.Speak
        return new Noise() with { .Sound = "Bark" }
    End Function
    Public Property Name As String Implements IAnimal.Name
End Class

Public Class Cat
    Implements IAnimal
    Public Function Speak() As Noise Implements IAnimal.Speak
        return new Noise() with { .Sound = "Meow" }
    End Function
    Public Property Name As String Implements IAnimal.Name
End Class

The below test produces the right output, and also works if IAnimal were an abstract base class with abstract function speak. If I understand correctly this means the covariant behavior is achieved, since it is kind of what you expect from inheritance.

 Public Sub ListenToAnimalsTest()
    dim spot = new Dog() With {.Name = "Spot" }
    dim kitty = new Cat() With {.Name = "Kitty" }

    Dim animalList As List(of IAnimal)
    animalList.Add(spot)
    animalList.Add(kitty)
    For Each animal in animalList 
        Console.WriteLine(animal.Name)
        animal.Speak().Listen()
    Next
End Sub

What I need is a way to make an animal that first barks and then meows if the following test worked I would have the pattern I need. and

Public Sub DogCatSpeak()
    dim spot = new Dog() With {.Name = "Spot" }
    spot.Speak().Listen()

    Dim spotBase As IAnimal = z
    Dim kitty As Cat = spotBase

    'Should output spot
    Console.WriteLine(y.Name)
    'Should output Meow
    kitty.Speak().Listen()

End Sub

I'm trying to work out if I can use contravariance to allow casting Animal or IAnimal to Cat or Dog, obviously only populating the common properties.

Any thoughts or suggestions?

Aucun commentaire:

Enregistrer un commentaire