List casting question

L

Leon Mayne

This is probably a bit of a n00b question, but here goes.

I have an interface in my business layer called IArchivable which includes
functions and properties for 'deleting' an object in the database without
actually deleting it. My functions in the business layer which return lists
of these objects always return all objects, whether they have been archived
or not (in case we want to display the deleted items to allow the user to
undelete them). I want to create a function which will filter out the
archived objects, and I'm using .NET 2.0 so I can't use LINQ.

I created a function with the following signature, which works fine:

Public Shared Function FilterArchived(Of T)(ByVal pList As Generic.List(Of
T)) As Generic.IList(Of T)

However, because the parameter is of T it's possible that someone could pass
in a collection of objects that does not implement IArchivable. Therefore I
tried changing the signature to:

Public Shared Function FilterArchived(Of T)(ByVal pList As Generic.List(Of
IArchivable)) As Generic.IList(Of T)

But this throws a runtime exception:

System.InvalidCastException was unhandled by user code
Message="Unable to cast object of type
'System.Collections.Generic.List`1[Bss.Target100.Europa.SafetyPolicySection]'
to type
'System.Collections.Generic.List`1[Bss.Target100.Europa.IArchivable]'."

(SafetyPolicySection implements IArchivable)

It would seem that the compiler is not smart enough to work out that the
container type implements the interface and cannot cast the object type. Is
there a way round this?
 
J

Jon Skeet [C# MVP]

Leon Mayne said:
This is probably a bit of a n00b question, but here goes.

I have an interface in my business layer called IArchivable which includes
functions and properties for 'deleting' an object in the database without
actually deleting it. My functions in the business layer which return lists
of these objects always return all objects, whether they have been archived
or not (in case we want to display the deleted items to allow the user to
undelete them). I want to create a function which will filter out the
archived objects, and I'm using .NET 2.0 so I can't use LINQ.

I created a function with the following signature, which works fine:

Public Shared Function FilterArchived(Of T)(ByVal pList As Generic.List(Of
T)) As Generic.IList(Of T)

However, because the parameter is of T it's possible that someone could pass
in a collection of objects that does not implement IArchivable. Therefore I
tried changing the signature to:

Public Shared Function FilterArchived(Of T)(ByVal pList As Generic.List(Of
IArchivable)) As Generic.IList(Of T)

But this throws a runtime exception:

System.InvalidCastException was unhandled by user code
Message="Unable to cast object of type
'System.Collections.Generic.List`1[Bss.Target100.Europa.SafetyPolicySection]'
to type
'System.Collections.Generic.List`1[Bss.Target100.Europa.IArchivable]'."

(SafetyPolicySection implements IArchivable)

It would seem that the compiler is not smart enough to work out that the
container type implements the interface and cannot cast the object type.

It's not that the compiler isn't smart enough - it's that a
List<SafetyPolicySection> really *isn't* a List<IArchivable>.
Consider what would happen if you tried to add some other IArchivable
implementation to the list, for instance...
Is there a way round this?

You really want to add a type constraint to T on your original
signature. I don't know how you'd do this in VB, but the equivalent in
C# would be:

public static IList<T> FilterArchived<T>(List<T> pList)
where T : IArchivable
 
L

Leon Mayne

Jon Skeet said:
You really want to add a type constraint to T on your original
signature. I don't know how you'd do this in VB, but the equivalent in
C# would be:

public static IList<T> FilterArchived<T>(List<T> pList)
where T : IArchivable

Aha! OK, I changed the signature to:

Public Shared Function FilterArchived(Of T As IArchivable)(ByVal pList As
Generic.List(Of T)) As Generic.IList(Of T)

Which works:

Error 4 Type argument 'Bss.Target100.Europa.FeatureItem' does not inherit
from or implement the constraint type 'Bss.Target100.Europa.IArchivable'

Thanks Jon.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top