Reputation: 89
I'got a problem with understanding why having such class:
public class Section<T> : ISection
where T : ISectionItem
{
public string Title { get; set; }
public LinkedList<T> Items { get; set; }
}
implementing such interface:
public interface ISection
{
string Title { get; set; }
LinkedList<ISectionItem> Items { get; set; }
}
I get compiler error saying:
Error 1
'JobTracker.Model.CV.Section<T>' does not implement interface member
'JobTracker.Model.CV.ISection.Items'.
'JobTracker.Model.CV.Section<T>.Items' cannot implement
'JobTracker.Model.CV.ISection.Items'
because it does not have the matching return type of
'System.Collections.Generic.IEnumerable<JobTracker.Model.CV.ISectionItem>'.
It should be possible, as T is guaranteed to be of type ISectionItem
. One of possible solutions problably would be to create addidiotional to or replace ISection
with generic ISection<T>
, but I dont know how it will behave when I will want to use it with Xaml. Is there any to let know the compiler that the interface meets the requirements?
EDIT1: Changed IEnumerable
to LinkedList
in ISection
as it was a bad concept and answers focus a bit aside from topic I was the most interested in.
EDIT2: My question was more directed on why T implementing ISectionItem
is not allowed, but I noticed how stupid I was. Interface ISection
allows usage of several different classes implementing ISectionItem
in one list Section<T>
does not.
Guys, both Your answers are correct but I will mark Olivier's as an answer as it alos shows the solution to this problem.
Upvotes: 0
Views: 593
Reputation: 112752
If you access Items
through the interface it would be possible to assign it a collection not being a LinkedList<T>
, which would result in an error. Since Items
also has a setter, it cannot be anything but IEnumerable<T>
; however, you can implement it like this
private LinkedList<T> _items;
public IEnumerable<T> Items {
get { return _items; }
set {
var linkedList = value as LinkedList<T>;
if (linkedList != null) {
_items = linkedList;
} else {
_items = new LinkedList<T>(value);
}
}
}
For this to work, you have to change the interface to:
public interface ISection<T>
where T : ISectionItem
{
string Title { get; set; }
IEnumerable<T> Items { get; set; }
}
and to declare the class like this
public class Section<T> : ISection<T>
where T : ISectionItem
{
...
}
Your edit does not solve the problem. Through your class you can assign a LinkedList<T>
of any T
implementing ISectionItem
; however your interface allows you to add a ISectionItem
different from T
.
class DerivedA : ISectionItem
{
...
}
class DerivedB : ISectionItem
{
...
}
ISection s = new Section<DerivedA>();
s.AddLast(new DerivedB()); // The collection in `s` is a `LinkedList<DerivedA>` boom!
The moral of the story is that the inheritance of the collection items (or in general: of the generic type parameters of some type) does NOT define the inheritance of the collection.
Let's T'
derive from T
.
Collection<T'>
derives from Collection<T>
==> false!
The two collections are just two different collections not having any assignment compatibility.
Upvotes: 2
Reputation: 152644
If you could make your Items
interface property read-only, the simplest route seems to be to add an explicit interface implementation as an overload:
public interface ISection
{
string Title { get; set; }
IEnumerable<ISectionItem> Items { get; }
}
public class Section<T> : ISection
where T : ISectionItem
{
public string Title { get; set; }
public LinkedList<T> Items { get; set; }
IEnumerable<ISectionItem> ISection.Items
{
get {return Items.Cast<ISectionItem>();}
}
}
Upvotes: 0
Reputation: 283911
It doesn't meet the requirements.
Consider the following
Section<ItemX> xSection = new Section<ItemX>;
//xSection.Items = BindingList<ISectionItem>();
ISection xISection = xSection;
xISection.Items = BindingList<ISectionItem>();
The contract from the interface is that Items
can be assigned to any collection of ISectionItem
.
Upvotes: 2