Reputation: 53
I have an interface and two classes which implement it. I'm getting a compiler error, and I'm not quite sure why.
interface IPerson
{
ICollection<string> NickNames{get;set;}
}
class ObservablePerson : IPerson
{
ObservableCollection<string> NickNames{get;set;}
}
class ListPerson : IPerson
{
List<string> NickNames{get;set;}
}
I'm having a bit of trouble understanding why this won't work, as List and ObservableCollection both implement ICollection.
Upvotes: 5
Views: 2793
Reputation: 57
I just ran into a similar problem, and a buddy of mine suggested an excellent solution: Generic types. Here's what you can do:
public interface IPerson<CollectionType> where CollectionType : ICollection<string>
{
CollectionType NickNames { get; set; }
}
class ObservablePerson : IPerson<ObservableCollection<string>>
{
public ObservableCollection<string> NickNames { get; set; }
}
public class ListPerson : IPerson<List<string>>
{
public List<string> NickNames { get; set; }
}
Here, "CollectionType" is a Generic, and can be named whatever you want (It's often called T throughout the .NET Framework, but giving it a meaningful name I feel is helpful). This will allow you to implement an interface on those ObservablePerson and ListPerson, while still having different types for the NickNames property on each (though any type that you use for CollectionType will need to implement ICollection).
Upvotes: 1
Reputation: 124790
I'm having a bit of trouble understanding why this won't work, as List and ObservableCollection both implement ICollection.
Yes, but the interface states that an ICollection<string>
is returned. The underlying type may be an ObservableCollection<string>
or a List<string>
, but the signature needs to conform to the interface. An ObservableCollection<string>
is an ICollection<string>
, but an ICollection<string>
is not necessarily an ObservableCollection<string>
.
Also, your methods need to be public (they are currently private). Interfaces don't deal with private or protected methods, it defines the public interface.
Upvotes: 6
Reputation: 7701
It should be
interface IPerson
{
ICollection<string> NickNames{get;set;}
}
class ObservablePerson : IPerson
{
ICollection<string> NickNames{get;set;}
}
class ListPerson : IPerson
{
ICollection<string> NickNames{get;set;}
}
And inside the implementation, you can return a List object or ObservableCollection
Edited code
interface IPerson
{
ICollection<string> NickNames{get;set;}
}
public class ObservablePerson : IPerson
{
ICollection<string> nickNames = new ObservableCollection<string>();
public ICollection<string> IPerson.NickNames
{
get
{
return nickNames;
}
set
{
nickNames = value;
}
}
}
public class ListPerson : IPerson
{
ICollection<string> nickNames = new List<string>();
public ICollection<string> IPerson.NickNames
{
get
{
return nickNames;
}
set
{
nickNames = value;
}
}
}
Upvotes: 1
Reputation: 2754
The compiler will insist on exact type matches, but you can shadow the property when accessed on the class (instead of through the interface). Note however, that when setting through the interface someone may assign a different kind of ICollection<string>
- so this would result in an exception.
interface IPerson
{
ICollection<string> NickNames { get; set; }
}
class ObservablePerson : IPerson
{
public new ObservableCollection<string> NickNames { get; set; }
ICollection<string> IPerson.NickNames
{
get { return NickNames; }
set { NickNames = (ObservableCollection<string>)value; }
}
}
class ListPerson : IPerson
{
public new List<string> NickNames { get; set; }
ICollection<string> IPerson.NickNames
{
get { return NickNames; }
set { NickNames = (List<string>)value; }
}
}
Upvotes: 0
Reputation: 8414
Your issue is that the compiler expects both of your subclasses to return a type of ICollection. You can return a List or ObservableCollection via the get accessor, but the declared member type needs to remain ICollection.
Upvotes: 0