- 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/
我不知道这是否可行,但基本上,我想公开一个 ReadOnlyCollection> 类型的属性,同时仍然能够在公开属性的类中修改基础集合。此外,我希望我的类的用户能够持有对返回集合的引用,以便它在我在
ReadOnlyCollection只支持读操作。为什么 T未标有 out关键字? 最佳答案 ReadOnlyCollection supports only reading operations 它
我想知道是否有人能指出我正确的方向...... 我如何从 ReadOnlyCollection 转换至 ReadOnlyCollection没有迭代或“更新”副本? 我正在使用 .NET Framew
这个问题在这里已经有了答案: Do not nest generic types in member signatures (1 个回答) 关闭 6 年前。 我正在修改我的所有代码以符合 FxCop
我有一个包含集合( Collection myItems )的类。我希望能够私下修改此 Collection 并通过公共(public)属性将其作为只读返回(如果可能,在 O(1) 中)。我正在考虑使
有这个代码... var b = new ReadOnlyCollection(new[] { 2, 4, 2, 2 }); b[2] = 3; 我在第二行收到编译错误。我预计会出现运行时错误,因为
我正在尝试使用 ReadOnlyCollection 使对象不可变,我希望对象的属性不可变。 public ReadOnlyCollection MyReadOnlyList { get
ReadOnlyCollection 构造函数要求您为它提供 IList。但是如果您有一些 ROC,您想要连接并生成一个新的 ROC,则 Concat 方法返回 IEnumerable。这不是传递给
在我的域对象中,我将 1:M 关系映射到 IList 属性。 为了更好的隔离,我这样设置为只读: private IList _property; public ReadOnlyCollection
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 9 年前。 Improve
MSDN含糊地提到: A ReadOnlyCollection)>) can support multiple readers concurrently, as long as the collect
假设一个方法看起来像这样。 Class MyClass public string ConcatenateList(ReadOnlyCollection aList) { var result =
我有一个具有 ReadOnlyCollection 的重线程应用程序,如下所示: internal static ReadOnlyCollection DistributorBackpressure4
我正在设计一些接口(interface)来使用 ReadOnlyCollection表明这些接口(interface)的使用者只能从集合中读取。 然而,所提供的集合并不是一成不变的,并且会不时发生变化
使用下面的代码我得到一个 CA2104 (DoNotDeclareReadOnlyMutableReferenceTypes) warning public readonly ReadOnlyColl
SO 上已经有几个类似的问题,但我发现没有一个真正涉及到这个特定主题,所以这里... 我的理解是,应该始终尝试通过具体类返回接口(interface)。不会深入探讨其背后的原因,已经有很多关于它的事情
此代码之所以有效,是因为 Enumerator无法修改集合: var roList = new List() { "One", "Two", "Three" }; IEnumerable objEnu
我使用 EntityFramewotk 和代码优先方法。所以,我这样描述我的模型: class Person { public long Id { get;set; } public
我有以下属性: private static Collection _loadedAssemblies = new Collection(); internal static ReadOnly
看来我做不到: private int[,] _table = new int[9, 9]; private ReadOnlyCollection _tableReadOnly = new ReadO
我是一名优秀的程序员,十分优秀!