- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我发布了一个similar question刚才关于参数,提到了an article与提倡使用 IReadOnlyCollection<T>
的这个问题更相关在 IEnumerable<T>
.
Lately, I’ve been considering the merits and demerits of returning
IEnumerable<T>
.On the plus side, it is about as minimal as an interface gets, so itleaves you as method author more flexibility than committing to aheavier alternative like
IList<T>
or (heaven forbid) an array.However, as I outlined in the last post, an
IEnumerable<T>
returnentices callers to violate the Liskov Substitution Principle. It’s tooeasy for them to use LINQ extension methods likeLast()
andCount()
,whose semanticsIEnumerable<T>
does not promise.What’s needed is a better way to lock down a returned collectionwithout making such temptations so prominent. (I am reminded of BarneyFife learning this lesson the hard way.)
Enter
IReadOnlyCollection<T>
, new in .NET 4.5. It adds just oneproperty toIEnumerable<T>
: theCount
property. By promising a count,you assure your callers that yourIEnumerable<T>
really does have aterminus. They can then use LINQ extension methods likeLast()
with aclear conscience.
然而,this article提倡使用ReadOnlyCollection<T>
(和其他替代方案)用于您想要保护成员的情况。
所以,我和一个同事讨论过这个问题,我们意见不一。
他建议一个方法应该返回它拥有的任何东西(例如 List<T>
或数组),如果该方法产生它并且调用者之后更改它不会对其他任何东西产生影响(即,它不是成员并且不'不属于任何生命周期大于方法调用的东西)。
我的观点是ReadOnlyCollection<T>
向调用者指示集合通常应保持原样。如果他们想更改它,那么他们就有责任将其显式转换为 IList<T>
。或调用ToList
在上面。
Microsoft guidelines具体状态:
In general, prefer
ReadOnlyCollection<T>
.
但除了声明使用 Collection<T>
之外,它似乎没有定义一般情况。用于返回读/写集合。但我同事的观点是,消费者可能想要添加到集合中,而我们不关心他们是否执行返回读/写集合的定义?
编辑
为了回答一些回复,为了尝试为我的问题添加更多上下文,我在下面放置了一些代码来演示与我的问题相关的评论的各种场景:
class Foo
{
private readonly int[] array = { 1 };
private readonly List<int> list = new List<int>(new[] {1});
// Get member array.
public int[] GetMemberArrayAsIs() => array;
public IEnumerable<int> GetMemberArrayAsEnumerable() => array;
public ReadOnlyCollection<int> GetMemberArrayAsReadOnlyCollection() => new ReadOnlyCollection<int>(array);
// Get local array.
public int[] GetLocalArrayAsIs() => new[] { 1 };
public IEnumerable<int> GetLocalArrayAsEnumerable() => new[] { 1 };
public ReadOnlyCollection<int> GetLocalArrayAsReadOnlyCollection() => new ReadOnlyCollection<int>(new[] { 1 });
// Get member list.
public Collection<int> GetMemberListAsIs() => new Collection<int>(list);
public IEnumerable<int> GetMemberListAsEnumerable() => array;
public ReadOnlyCollection<int> GetMemberListAsReadOnlyCollection() => new ReadOnlyCollection<int>(array);
// Get local list.
public Collection<int> GetLocalListAsIs() => new Collection<int>(new[] { 1 });
public IEnumerable<int> GetLocalListAsEnumerable() => new List<int>(new[] { 1 });
public ReadOnlyCollection<int> GetLocalListAsReadOnlyCollection() => new List<int>(new[] { 1 }).AsReadOnly();
}
class FooTest
{
void Test()
{
var foo = new Foo();
int count;
// Get member array.
var array1 = foo.GetMemberArrayAsIs(); // ReSharper encourages to make the return type IEnumerable<T>.
count = array1.Length; // ...unless we do this.
var enumerable1 = foo.GetMemberArrayAsEnumerable();
enumerable1.Concat(enumerable1); // Warning of possible multiple enumeration.
var roc1 = foo.GetMemberArrayAsReadOnlyCollection(); // ReSharper encourages to make the return type IEnumerable<T>.
count = roc1.Count; // ...unless we do this.
// Get local array.
var array2 = foo.GetLocalArrayAsIs(); // ReSharper encourages to make the return type IEnumerable<T>.
count = array2.Length; // ...unless we do this.
var enumerable2 = foo.GetLocalArrayAsEnumerable();
enumerable2.Concat(enumerable2); // Warning of possible multiple enumeration.
var roc2 = foo.GetLocalArrayAsReadOnlyCollection(); // ReSharper encourages to make the return type IEnumerable<T>.
count = roc2.Count; // ...unless we do this.
// Get member list.
var list1 = foo.GetMemberListAsIs(); // ReSharper encourages to make the return type IEnumerable<T>.
count = list1.Count; // ...unless we do this.
list1.Add(2); // This affects the Foo object as the collection is a member. DANGEROUS!
var enumerable3 = foo.GetMemberListAsEnumerable();
enumerable3.Concat(enumerable3); // Warning of possible multiple enumeration.
var roc3 = foo.GetMemberListAsReadOnlyCollection(); // ReSharper encourages to make the return type IEnumerable<T>.
count = roc3.Count; // ...unless we do this.
// Get local list.
var list2 = foo.GetLocalListAsIs(); // ReSharper encourages to make the return type IEnumerable<T>.
count = list2.Count; // ...unless we do this.
list2.Add(2); // This doesn't affect the Foo object as the collection was produced by the method.
var enumerable4 = foo.GetLocalListAsEnumerable();
enumerable4.Concat(enumerable4); // Warning of possible multiple enumeration.
var roc4 = foo.GetLocalListAsReadOnlyCollection(); // ReSharper encourages to make the return type IEnumerable<T>.
count = roc4.Count; // ...unless we do this.
}
}
所以用一个例子来说明这个困境,如果我们取 GetMemberArrayAsIs
,ReSharper 告诉我将返回类型更改为 IEnumerable<T>
如果调用代码仅枚举返回值一次。如果我多次枚举返回值,那么我必须保持原样,以避免可能出现的多次枚举警告。然而,这就是我的问题所在。我应该返回 ReadOnlyCollection<T>
而不是返回数组吗?遵守我对 Microsoft 准则的理解?这需要我实例化一个 ReadOnlyCollection<T>
如图GetMemberArrayAsReadOnlyCollection
.或者,我们是否应该像我的同事认为的那样返回数组 (GetMemberArrayAsIs
)?
或者,我可以坚持返回 IEnumerable<T>
并让调用者有责任在多次使用集合之前进行枚举,但我认为微软更喜欢使用 ReadOnlyCollection<T>
就是为了避免这种情况。
如果是 List<T>
, 困境稍微复杂一些,因为它有可能被改变,如果它是成员,这是一个问题。在这种情况下,我当然应该返回 ReadOnlyCollection<T>
(GetMemberListAsReadOnlyCollection
)。但是对于本地列表,我应该返回 ReadOnlyCollection<T>
吗?遵守我对 Microsoft 准则的理解?这需要我实例化一个 ReadOnlyCollection<T>
如图GetLocalListAsReadOnlyCollection
.或者,我们是否应该像我的同事认为的那样返回列表 (GetMemberListAsIs
)?
我希望这能为这个问题增加更多的背景,并且在某些方面它是相当哲学的。但其中很多是关于应如何解释 Microsoft 指南,以及是否应由提供商承担转换为 ReadOnlyCollection<T>
的责任。 ,或者让消费者在多次使用之前枚举返回的值(使用 ToArray
),或者实际上两者都没有并按原样返回。
最佳答案
这个问题可能会被关闭,因为它含糊不清并且没有唯一的正确答案,但无论如何我都会尝试。
我会说,如果你返回一个 List<T>
的对象或 T[]
,您可能希望将其公开为至少 IReadOnlyCollection<T>
或更好 IReadOnlyList<T>
它具有索引器支持。这样做的好处是:
ToList
不需要对同一输出进行多次枚举。IReadOnlyList<T>
,您可以使用 for
进行枚举循环而不是 foreach
,这在某些极端情况下可能是有利的。我看到的主要缺点,根据实现情况可能是一个很大的缺点:
IEnumerable<T>
以流式传输方式(例如从 Stream
或 IDbDataReader
等读取)。这意味着在您的代码中引入重大更改。关于使用IList<T>
对比IReadOnlyList<T>
或 IReadOnlyCollection<T>
,只要您总是返回列表的副本就可以了。如果您有一个保存在内存中的列表,您不希望调用者修改它。
关于c# - 对返回类型使用 ReadOnlyCollection<T> 与 List<T> 与数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49281644/
我想使用 R 预定义这样的列表 DATA<-list( list(list(),list(),list()), list(list(),list(),list()), list(list(),l
如何将一个列表添加到另一个列表,返回一个列表的列表? foo :: [a] -> [a] -> [[a]] 例如,我想要的结果是: foo [1,2] [3,4] 将是 [[1,2], [3,4]]。
我还没有在这里找到类似问题的解决方案,所以我会寻求你的帮助。 有 2 个列表,其中之一是列表列表: categories = ['APPLE', 'ORANGE', 'BANANA'] test_re
这个问题不同于Converting list of lists / nested lists to list of lists without nesting (这会产生一组非常具体的响应,但无法解决
原始列表转换为 List正好。为什么原始列表的列表不能转换为 List 的列表? { // works List raw = null; List wild = raw; } {
在下面的代码中,get()被调用并将其结果分配给类型为 List> 的变量. get()返回 List>并在类型参数为 T 的实例上调用设置为 ? ,所以它应该适合。 import java.util
原始列表转换为 List正好。为什么原始列表的列表不能转换为 List 的列表? { // works List raw = null; List wild = raw; } {
在insufficiently-polymorphic 作者说: def foo[A](fst: List[A], snd: List[A]): List[A] There are fewer way
我有下面的代码有效。 class ListManipulate(val list: List, val blockCount: Int) { val result: MutableList>
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 5 年前。 Improve this ques
在 scala (2.9) 中转换列表列表的最佳方法是什么? 我有一个 list : List[List[A]] 我想转换成 List[A] 如何递归地实现这一点?或者还有其他更好的办法吗? 最佳答案
我编写了这个函数来确定给定元素是否存储在元组列表的列表中,但目前它只搜索第一个列表。我将如何搜索其余列表? fun findItem (name : command, ((x,y)::firstlis
我创建了一个类名 objectA,它有 4 个变量:约会时间;字符串文本;变量 1,变量 2 我需要创建一个 ObjectA() 列表。然后首先按时间对它们进行分组,其次按 var1,然后按 var2
我有一套说法 char={'J','A'} 和列表的列表 content = [[1,'J', 2], [2, 'K', 3], [2, 'A', 3], [3,'A', 9], [5, 'J', 9
我有以下列表 List >>> titles = new ArrayList >>> ();我想访问它的元素,但我不知道该怎么做.. 该列表有 1 个元素,它又包含 3 个元素,这 3 个元素中的
转换 List[List[Long]] 的最佳方法是什么?到 List[List[Int]]在斯卡拉? 例如,给定以下类型列表 List[List[Long]] val l: List[List[Lo
我有一个来自 Filereader (String) 的 List-List,如何将其转换为 List-List (Double):我必须返回一个包含 line-Array 的第一个 Values 的
我收集了List> 。我需要将其转换为List> 。这是我尝试过的, List> dataOne = GetDataOne(); var dataTwo = dataOne.Select(x => x
这个问题在这里已经有了答案: Cannot convert from List to List> (3 个答案) 关闭 7 年前。 我没有得到这段代码以任何方式编译: List a = new Ar
这个问题在这里已经有了答案: Cannot convert from List to List> (3 个答案) 关闭 7 年前。 我没有得到这段代码以任何方式编译: List a = new Ar
我是一名优秀的程序员,十分优秀!