返回派生类型时"未实现接口"

Dan*_*iel 39 c#

以下代码:

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; } }
}
Run Code Online (Sandbox Code Playgroud)

产生以下错误:

错误CS0738:'InheritanceTest.MyData'未实现接口成员'InheritanceTest.ISomeData.Data'.'InheritanceTest.MyData.Data'无法实现'InheritanceTest.ISomeData.Data',因为它没有匹配的返回类型'System.Collections.Generic.IEnumerable'.

由于List <T>实现了IEnumerable <T>,因此可以认为我的类将实现该接口.有人可以解释一下这个不编译的理由是什么吗?

我可以看到,有两种可能的解决方案:

  1. 将接口更改为更具体,并要求实现IList.
  2. 更改我的类(MyData)以返回IEnumerable并实现原始接口.

现在假设我也有以下代码:

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>";
    }
}
Run Code Online (Sandbox Code Playgroud)

我可以更改我的接口以要求实现IList(选项1),但是这限制了谁可以实现接口以及可以传递给ConsumerA的类的数量.或者,我可以更改实现(类MyData),以便它返回IEnumerable而不是List(选项2),但然后必须重写ConsumerB.

这似乎是C#的一个缺点,除非有人可以启发我.

STW*_*STW 27

对于您想要做的事情,您可能希望使用返回List而不是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
}
Run Code Online (Sandbox Code Playgroud)

编辑: 为了澄清,这使MyData类在被视为MyData的实例时返回List; 同时仍然允许它在被视为ISomeData的实例时返回IEnumerable的实例.


Sol*_*ogi 24

不幸的是,返回类型必须匹配.您正在寻找的是"返回类型协方差",C#不支持这一点.

http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=90909

C#Compiler团队的高级开发人员Eric Lippert在他的博客中提到他们不打算支持返回类型的协方差.

"这种方差被称为"返回类型协方差".正如我在本系列的早期提到的那样,(a)这个系列不是关于那种方差,(b)我们没有计划实现这种方差. C#. "

http://blogs.msdn.com/ericlippert/archive/2008/05/07/covariance-and-contravariance-part-twelve-to-infinity-but-not-beyond.aspx

值得阅读Eric关于协方差和逆变的文章.

http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx

  • 为什么不支持这个?似乎合乎逻辑? (2认同)
  • 2020年看了你的回答,这个功能还没有实现吗?! (2认同)

Ken*_* K. 5

What if you accessed your MyData object trough the ISomeData interface? In that case, IEnumerable could be of an underlying type not assignable to a List.

IEnumerable<string> iss = null;

List<string> ss = iss; //compiler error
Run Code Online (Sandbox Code Playgroud)

EDIT:

I understand what you mean from your comments.

Anyway, what I would do in your case would be:

    public interface ISomeData<T> where T: IEnumerable<string>
    {
        T Data { get; }
    }

    public class MyData : ISomeData<List<string>>
    {
        private List<string> m_MyData = new List<string>();
        public List<string> Data { get { return m_MyData; } }
    }
Run Code Online (Sandbox Code Playgroud)

Converting to generic Interface with appropriate constraint offers I think the best of both flexibility and readability.