0

I am getting an Invalid Cast Exception when doing Bar = IFoo but not when Bar = Foo even though that during run time the IFoo object is of Type Foo. The issue here is that the assemblies that work with the Bar Class should not not know about the Foo class. Foo is an DbEntity and Bar is what contains all the Business logic for Foo. I could use a Factory method in Bar but operators are just so convenient! Especially when getting Foo back out of Bar for database operations outside of the Bar class.

When trying to figure out what is going on I stumbled across this article, which is really interesting but does not offer any solutions to a situation like this. I don't know much about these kinds of odd runtime exceptions, so is there any way I can keep things separated out like I want them? Using a factory for Bar seems like the simplest method but I would like to know if there is a workaround in case I run into something like this again where that's not an option.

In Assembly referenced by all other Assemblies:

Namespace ISpace

  Public Interface IFoo
  End Interface

  Public Interface IBar
    ReadOnly Property SomeProperty As Integer
  End Interface

End Namespace

In Assembly that should only be referenced by the Bar Class's Assembly

Namespace FooSpace

  Public Class Foo : Implements ISpace.IFoo
    Public SomeProperty As Integer
  End Class

End Namespace

In Bar Class's Assembly

Namespace BarSpace

  Public Class Bar : Implements ISpace.IBar

    ReadOnly _value As FooSpace.Foo

    Private Sub New(value As FooSpace.Foo)
      _value = value
    End Sub

    Public ReadOnly Property SomeProperty As Integer Implements IBar.SomeProperty
      Get
        Return _value.SomeProperty
      End Get
    End Property

    Public Shared Widening Operator CType(ByVal value As FooSpace.Foo) As Bar
      Return New Bar(value)
    End Operator

    Public Shared Narrowing Operator CType(ByVal value As Bar) As FooSpace.Foo
      Return value._value
    End Operator
  End Class

End Namespace

In an Assembly that should only reference the Bar Class's Assembly

Namespace TestSpace

  Public Class FooBarTest
    Public Shared Function GetMeBarFromFooFail(Foo As ISpace.IFoo) As IBar
      Dim bor As BarSpace.Bar
      bor = Foo 'Throws InvalidCastException
      Return bor
    End Function

    Public Shared Function GetMeBarFromFooPass(foo As ISpace.IFoo) As IBar
      Dim foofoo As FooSpace.Foo = foo
      Dim bar As BarSpace.Bar
      bar = foofoo 'No Exception
      Return bar
    End Function

  End Class

End Namespace
  • I'm not sure why you would expect it to work. In your example, you're casting an `IFoo` variable to `Bar`, but Bar doesn't implement `IFoo`, so they aren't even remotely compatible. I suppose if you had a `DerivedBar` class that inherited `Bar`, then and that `DerivedBar` class implemented `IFoo`, then it would work, but you certainly don't include that in your example. In any case, turn Option Strict On`. It will serve you well in such situations. – Steven Doggart Jul 28 '18 at 20:23
  • Also, in the future, I'd recommending using slightly more real world examples. Foo and Bar are meaningless and make the example unnecessarily confusing. They're fine for a small snippet, but for a complex inheritance structure, something like `IFruit` and `Apple` would help make the relationships much more obvious. – Steven Doggart Jul 28 '18 at 20:25

0 Answers0