The following code:
public interface ISomeData
{
IEnumerable Data { get; }
}
public class MyData : ISomeData
{
private List
If you need to have a list in your interface (known number of items with random access), you should then consider changing the interface to
public interface ISomeData
{
ICollection<string> Data { get; }
}
This will give you both the extensibility and the features you need from a list.
List<T>
cannot be easily subclassed, meaning that you might have trouble returning that exact type from all the classes that want to implement your interface.
ICollection<T>
on the other hand, can be implemented in various ways.
I would choose option 2:
The point to define an interface in your code is to define an contract, and so you and other people who implement your interface know what to agree on. Whether you define IEnumerable or List in your interface is really an contract issue and belong to framework design guideline. Here is a whole book to discuss this.
Personally , I would expose IEnumerable and implement MyData to IEnumerable, and you can cast it back to List in RandomAccess() method.
Unfortunately, the return type must match. What you are looking for is called 'return type covariance' and C# doesn't support that.
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=90909
Eric Lippert, senior developer on C# Compiler team, mentions on his blog that they don't plan to support return type covariance.
"That kind of variance is called "return type covariance". As I mentioned early on in this series, (a) this series is not about that kind of variance, and (b) we have no plans to implement that kind of variance in C#. "
http://blogs.msdn.com/ericlippert/archive/2008/05/07/covariance-and-contravariance-part-twelve-to-infinity-but-not-beyond.aspx
It's worth reading Eric's articles on covariance and contravariance.
http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx
Interfaces require that the signature of the method match with the signature of the contract exactly.
Here is a simpler example that also will not compile:
interface IFoo
{
Object GetFoo();
}
class Foo : IFoo
{
public String GetFoo() { return ""; }
}
Now as for what to do about it I would let the interface dictate the implementation. If you want the contract to be IEnumerable<T>
then that is what it should be in the class as well. The interface is the most important thing here as the implementation is free to be as flexible as it needs to be.
Just be certain that IEnumerable<T>
is the best choice here. (This is all highly subjective as I don't know much about your domain or the purpose of these types in your application. Good luck!)
For what you want to do you'll probably want to implement the interface explicitly with a class (not interface) member that returns the List instead of IEnumerable...
public class MyData : ISomeData
{
private List<string> m_MyData = new List<string>();
public List<string> Data
{
get
{
return m_MyData;
}
}
#region ISomeData Members
IEnumerable<string> ISomeData.Data
{
get
{
return Data.AsEnumerable<string>();
}
}
#endregion
}
Edit: For clarification, this lets the MyData class return a List when it is being treated as an instance of MyData; while still allowing it to return an instance of IEnumerable when being treated as an instance of ISomeData.
What if you changed your interface to extend IEnumerable so you can enumerate the object and edit the data via the class property.
public interface ISomeData : IEnumerable<string>
{
IEnumerable<string> Data { get; }
}
public class MyData : ISomeData
{
private List<string> m_MyData = new List<string>();
public List<string> Data { get { return m_MyData; }
public IEnumerator<string> GetEnumerator()
{
return Data;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}