Casting Rules
by Aeden Jameson on 11/2/2007 8:57:00 AM
Suppose I have the follwing
Public Interface IEntity
End Interface
Public Class TestEntity
Implements IEntity
End Class
Public Interface IRepository(Of T As {IEntity})
End Interface
Public Interface IConcreteRepository
Inherits IRepository(Of TestEntity)
End Interface
Public Class ConcreteRepository
Implements IConcreteRepository
End Class
Public Class Factory
Public Shared Function Create(Of TRepository As {Class,
IRepository(Of TEntity)}, TEntity As {IEntity})()
Return New ConcreteRepository()
End Function
End Class
I get casting exception on the line
Dim Repository As IRepository(Of IEntity) = Factory.Create(Of
IConcreteRepository, TestEntity)()
What am I missing?
The exception states
Unable to cast object of type 'ConcreteRepository' to type
'IRepository`1[IEntity]'.
Cheers,
Aeden
Re: Casting Rules
by Peter Duniho on 11/2/2007 9:40:00 AM
On 2007-11-02 15:57:23 -0700, Aeden Jameson <aeden.jameson@gmail.com> said:
> [...]
> I get casting exception on the line
>
> Dim Repository As IRepository(Of IEntity) = Factory.Create(Of
> IConcreteRepository, TestEntity)()
>
> What am I missing?
>
> The exception states
>
> Unable to cast object of type 'ConcreteRepository' to type
> 'IRepository`1[IEntity]'.
I believe this is because generics don't support covariant generics.
Your ConcreteRepository class implements IConcreteRepository, which
inherits IRepository<TestEntity>, and not IRepository<IEntity>. You
would need the latter in order to successfully perform the cast.
The reasoning behind this has to do with what a generic class _could_
do with the concrete type for the class. In particular, if you could
cast down to a base class like that, then the possibility would arise
that something in the generic class would replaces some instance of
TestEntity with some instance of a different IEntity-derived class,
which would cause a problem later in the code that had the
TestEntity-specific concrete class.
By requiring the generic type parameter to always be the actual type,
this sort of problem is avoided. It does lead to less-flexible code
such as in the example you're running into, but along with that comes
compile-time type safety.
If you don't want compile-time type safety, you should either not use
generics, or make the IRepository<> generic use IEntity instead of
TestEntity.
Pete