Casting problems in related classes
Here's a refined version of the classes I have.
public abstract class BaseParent { }
public abstract class ChildCollectionItem<T>
where T : BaseParent
{
// References a third-party object that acts as the parent to both the collection
// items and the collection itself.
public T parent;
// References the collection to which this item belongs. The owning collection
// will share the same parent type. The second type argument indicates what
// type of items the collection will store.
public ChildCollection<T, ChildCollectionItem<T>> owningCollection;
}
public abstract class ChildCollection<T, U> : CollectionBase
where T : BaseParent
where U : ChildCollectionItem<T>
{
// References a third-party object that acts as the parent to both the collection
// items and the collection itself.
public T parent;
// Adds an item of type 'U' to the collection. When added, I want to set the
// owningCollection value of the item to 'this' collection.
public int Add(U item)
{
int indexAdded = this.List.Add(item);
// THIS LINE IS THROWING A COMPILE ERROR - Cannot convert type
// 'ChildCollection<T, U>' to 'ChildCollection<T, ChildCollectionItem<T>>'
item.owningCollection = this;
return indexAdded;
}
I understand that this problem is probably due to the fact that the ChildCollection class does not know the type constraints set on the ChildCollectionItem, because if it did, there would be no problem here. Type 'U' must always be a ChildCollectionItem, where ChildCollectionItem 'T' is always the same as ChildCollection 'T'.
I need to know if there is a way that I can use 'this' so that it compiles or modifies my classes / constraints so the compiler can handle this without casting.
The problem is variance - U can be a different type than just ChildCollectionItem<T>
- it can be a type derived from ChildCollectionItem<T>
and Foo<DerivedClass>
not compatible with Foo<BaseClass>
.
How about introducing another base class in ChildCollection<T, U>
?
using System.Collections;
public abstract class BaseParent { }
public abstract class ChildCollectionItem<T>
where T : BaseParent
{
public T parent;
public ChildCollection<T> owningCollection;
}
public abstract class ChildCollection<T> : CollectionBase
where T : BaseParent
{
}
public abstract class ChildCollection<T, U> : ChildCollection<T>
where T : BaseParent
where U : ChildCollectionItem<T>
{
public T parent;
public int Add(U item)
{
int indexAdded = this.List.Add(item);
item.owningCollection = this;
return indexAdded;
}
}
source to share
this problem is probably due to the fact that the ChildCollection class does not know the type of constraints set on the ChildCollectionItem, because if that were there there should be no problem.
The above statement is not correct.
Type 'U' must always be ChildCollectionItem, where ChildCollectionItem 'T' is always the same as ChildCollection 'T'.
How do you understand this? U is guaranteed, through its constraint, to be convertible by reference conversion to this type. The type that is required is not guaranteed. U can be any type derived from that type.
If U is always a type, then why is "U" in the first place? Why not just eliminate the type parameter entirely and replace all of its use with the type you expect?
source to share