Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Interface not implemented" when Returning Derived Type

Tags:

c#

The following code:

public interface ISomeData {     IEnumerable<string> Data { get; } }  public class MyData : ISomeData {     private List<string> m_MyData = new List<string>();     public List<string> Data { get { return m_MyData; } } } 

Produces the following error:

error CS0738: 'InheritanceTest.MyData' does not implement interface member 'InheritanceTest.ISomeData.Data'. 'InheritanceTest.MyData.Data' cannot implement 'InheritanceTest.ISomeData.Data' because it does not have the matching return type of 'System.Collections.Generic.IEnumerable'.

Since a List<T> implements IEnumerable<T>, one would think that my class would implement the interface. Can someone explain what the rationale is for this not compiling?

As I can see it, there are two possible solutions:

  1. Change the interface to be more specific and require IList be implemented.
  2. Change my class (MyData) to return IEnumerable and implement the original interface.

Now suppose I also have the following code:

public class ConsumerA {     static void IterateOverCollection(ISomeData data)     {         foreach (string prop in data.MyData)         {             /*do stuff*/         }     } }  public class ConsumerB {     static void RandomAccess(MyData data)     {          data.Data[1] = "this line is invalid if MyPropList return an IEnumerable<string>";     } } 

I could change my interface to require IList to be implemented (option 1), but that limits who can implement the interface and the number of classes that can be passed into ConsumerA. Or, I could change implementation (class MyData) so that it returns an IEnumerable instead of a List (option 2), but then ConsumerB would have to be rewritten.

This seems to be a shortcoming of C# unless someone can enlighten me.

like image 456
Daniel Avatar asked Jul 13 '09 18:07

Daniel


People also ask

Can interface methods have return type in C#?

Answers. By definition of what an interface is it is impossible to return an interface because interfaces cannot be allocated; there cannot be anything to return.

Can interface implement interface?

An interface can extend any number of interfaces but one interface cannot implement another interface, because if any interface is implemented then its methods must be defined and interface never has the definition of any method.

In which case we can implement only required methods of an interface?

Explanation: In case of adapter class, we can implement only required methods of any interface.

Can interface contain variables?

Like a class, an interface can have methods and variables, but the methods declared in an interface are by default abstract (only method signature, no body). Interfaces specify what a class must do and not how.


2 Answers

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

like image 149
SolutionYogi Avatar answered Sep 19 '22 16:09

SolutionYogi


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.

like image 24
STW Avatar answered Sep 19 '22 16:09

STW