If I read it correctly... then the problem is that just because Foo : Bar
, that does not mean that ISomething<Foo> : ISomething<Bar>
...
In some cases, variance in C# 4.0 may be an option. Alternatively, there are sometimes things you can do with generic methods (not sure it will help here, though).
The closest you can do in C# 3.0 (and below) is probably a non-generic base interface:
interface IFolderOrItem {}
interface IFolderOrItem<TFolderOrItem> : IFolderOrItem
where TFolderOrItem : FolderOrItem { }
commonly, the base-interface would have, for example, a Type ItemType {get;}
to indicate the real type under consideration. Then usage:
IFolderOrItem SelectedItem { get; set; }
...
public void SomeMagicMethod()
{
this.SelectedItem = GetMagicDocument(); // no cast needed
// not **so** bad
}
From the spec, this relates to §25.5.6 (ECMA 334 v4):
25.5.6 Conversions
Constructed types follow the same conversion rules (§13)
as do non-generic types. When applying
these rules, the base classes and
interfaces of constructed types shall
be determined as described in §25.5.3.
No special conversions exist between
constructed reference types other than
those described in §13. In particular,
unlike array types, constructed
reference types do not permit
co-variant conversions (§19.5). This
means that a type List<B>
has no
conversion (either implicit or
explicit) to List<A>
even if B
is
derived from A
. Likewise, no
conversion exists from List<B>
to
List<object>
.
[Note: The rationale for
this is simple: if a conversion to
List<A>
is permitted, then apparently,
one can store values of type A
into
the list. However, this would break
the invariant that every object in a
list of type List<B>
is always a value
of type B
, or else unexpected failures
can occur when assigning into
collection classes. end note]
The same applies to interfaces. This changes a bit in C# 4.0, but only in some cases.