如果返回类型是可枚举的,则返回列表是错误的

HCL*_*HCL 13 c#

我经常遇到想要Enumerable<T>从方法或属性返回的情况.为了构建返回Enumerable<T>,我使用List<T>-instance.填写列表后,我返回列表.

我一直认为这就够了.但它存在这样的可能性:调用者将结果投射Enumerable<T>回List<T>并开始进一步使用它.如果稍后我更改了我的方法的实现,则调用者的代码将失败.为了避免这种情况,我可以返回list.ToArray或制作一个只读列表,然后再将其返回给调用者.但对我来说,这似乎是一个很大的矫枉过正.你怎么看?

请注意,我永远不会返回内部使用的列表,以便调用者可以更改我的对象内部状态.问题只是关于一个简短的生活清单,它是临时建立的,用于保存返回值.

IEnumerable<string> GetAList() {
    List<string> aList = new List<string>();
    aList.Add("a");
    aList.Add("b");
    return aList;
}

IEnumerable<string> GetAList() {
    List<string> aList = new List<string>();
    aList.Add("a");
    aList.Add("b");
    return aList.ToArray<string>();
}
Run Code Online (Sandbox Code Playgroud)

这些例子非常简单,在这种情况下,我会从一开始就使用数组,但它只是为了解释这个问题.

Aak*_*shM 15

调用者将结果Enumerable<T>重新投入List<T>并开始进一步工作的可能性

如果您的实施发生变化,那么只有这样做的调用者才会受到指责.你保证会返回Enumerable- 只要你继续这样做,你就不能对那些假设不止于此的来电者的问题负责.

还要注意@Chris提到的内容 - 可能存在政治问题,这些问题在某些时候甚至要求你保持向后兼容性,即使是那些"违反规则"的呼叫者--Raymond Chen(在应用程序兼容性团队中为Microsoft工作)有一个完整的博客"当这个应用程序在操作系统版本x + 1上中断"时产生的恶作剧故事不是一个可接受的答案......


Dr *_*bie 14

不,这很好.

这是工作中"多态"的一个例子.因为方法的调用者只对a感兴趣,IEnumerable<string>所以只要方法派生自IEnumerable<string>接口,该方法的内部工作就可以自由地返回它喜欢的任何类.

如果调用者接受IEnumerable<string>并强制转换,List<string>则他们违反了合同,该合同仅声明'IEnumerable<string>将返回合同.


Mar*_*tos 6

您可以从方法内部生成列表的元素,从而防止调用者的任何类型的错误行为:

IEnumerable<string> GetAList() {
    List<string> aList = new List<string>();
    aList.Add("a");
    aList.Add("b");
    foreach (string s in aList)
        yield return s;
}
Run Code Online (Sandbox Code Playgroud)

当然,您通常可以在生成值时生成值,从而完全避免列表:

IEnumerable<string> GetAList() {
    yield return "a";
    yield return "b";
}
Run Code Online (Sandbox Code Playgroud)

  • 以这种方式使用yield确实会产生您需要注意的影响.例如,Enumerable.Count扩展方法使用as运算符尝试强制转换为ICollection,并且仅枚举此强制转换是否失败.此外,如果调用者多次枚举结果,那么如果使用yield,则整个方法将被执行多次 - 如果返回集合,则只执行一次. (5认同)
  • @HCL:我说在很多方面它不是你的问题,但另一方面,如果你的代码可以被轻微地重构以防止他人滥用,那么这似乎是一个好主意.毕竟,如果你将来改变并且他们的代码停止工作,那么他们的错是你的错,你认为他们会因为你的改变而烦恼吗?这可能不是你的责任,但这并不意味着它不会成为你的问题. (2认同)