Here's a thinned out 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>
{
开发者_如何学Python // 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 realize this problem is probably due to the fact that the ChildCollection class isn't aware of the type constraints set in ChildCollectionItem, because if it was there shouldn't be a problem here. Type 'U' should always be a ChildCollectionItem where the ChildCollectionItem 'T' is always the same as the ChildCollection 'T'.
What I need to know is if there is a way I can cast 'this' so that it compiles, or modify my classes / constraints so the compiler can handle this without a cast.
The problem is one of variance - U could be some type other than just ChildCollectionItem<T>
- it could be a type derived from ChildCollectionItem<T>
, and Foo<DerivedClass>
isn't compatible with Foo<BaseClass>
.
How about introducing another generic base class to 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;
}
}
this problem is probably due to the fact that the ChildCollection class isn't aware of the type constraints set in ChildCollectionItem, because if it was there shouldn't be a problem here.
The statement above is incorrect.
Type 'U' should always be a ChildCollectionItem where the ChildCollectionItem 'T' is always the same as the ChildCollection 'T'.
How do you figure that? U is guaranteed via its constraint to be convertible via reference conversion to that type. It is not guaranteed to be that type, which is what is required. U could be any type derived from that type.
If U is always that type, then why is there a "U" in the first place? Why not just eliminate the type parameter entirely and replace every usage of it with the type you expect it to be?
Your constraint on U is very specific; U has to be of type ChildCollectionItem. Would it be possible in your application to define the collection as
public abstract class ChildCollection<T, ChildCollectionItem<T>>
That would eliminate the need to cast.
精彩评论