- 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/
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
在编码时,我问了自己这个问题: 这样更快吗: if(false) return true; else return false; 比这个? if(false) return true; return
如何在逻辑条件下进行“返回”? 在这样的情况下这会很有用 checkConfig() || return false; var iNeedThis=doSomething() || return fa
这是我的正则表达式 demo 如问题所述: 如果第一个数字是 1 则返回 1 但如果是 145 则返回 145 但如果是 133 则返回 133 样本数据a: K'8134567 K'81345678
在代码高尔夫问答部分查看谜题和答案时,我遇到了 this solution返回 1 的最长和最晦涩的方法 引用答案, int foo(void) { return! 0; } int bar(
我想在下面返回 JSON。 { "name": "jackie" } postman 给我错误。说明 Unexpected 'n' 这里是 Spring Boot 的新手。 1日龄。有没有正确的方法来
只要“is”返回 True,“==”不应该返回 True 吗? In [101]: np.NAN is np.nan is np.NaN Out[101]: True In [102]: np.NAN
我需要获取所有在 6 号或 7 号房间或根本不在任何房间的学生的详细信息。如果他们在其他房间,简单地说,我不希望有那个记录。 我的架构是: students(roll_no, name,class,.
我有一个表单,我将它发送到 php 以通过 ajax 插入到 mysql 数据库中。一切顺利,php 返回 "true" 值,但在 ajax 中它显示 false 消息。 在这里你可以查看php代码:
我在 Kotlin 中遇到了一个非常奇怪的无法解释的值比较问题,以下代码打印 假 data class Foo ( val a: Byte ) fun main() { val NUM
请注意,这并非特定于 Protractor。问题在于 Angular 2 的内置 Testability service Protractor 碰巧使用。 Protractor 调用 Testabil
在调试窗口中,以下表达式均返回 1。 Application.WorksheetFunction.CountA(Cells(4 + (i - 1) * rows_per_record, 28) & "
我在本地使用 jsonplaceholder ( http://jsonplaceholder.typicode.com/)。我正在通过 extjs rest 代理测试我的 GET 和 POST 调用
这是 Postman 为成功调用我的页面而提供的(修改后的)代码段。 var client = new RestClient("http://sub.example.com/wp-json/wp/v2
这个问题在这里已经有了答案: What to do with mysqli problems? Errors like mysqli_fetch_array(): Argument #1 must
我想我对 C 命令行参数有点生疏。我查看了我的一些旧代码,但无论这个版本是什么,都会出现段错误。 运行方式是 ./foo -n num(其中 num 是用户在命令行中输入的数字) 但不知何故它不起作用
我已经编写了一个类来处理命名管道连接,如果我创建了一个实例,关闭它,然后尝试创建另一个实例,调用 CreateFile() 返回 INVALID_HANDLE_VALUE,并且 GetLastErro
即使 is_writable() 返回 true,我也无法写入文件。当然,该文件存在并且显然是可读的。这是代码: $file = "data"; echo file_get_contents($fil
下面代码中的变量 $response 为 NULL,尽管它应该是 SOAP 请求的值。 (潮汐列表)。当我调用 $client->__getLastResponse() 时,我从 SOAP 服务获得了
我一直在网上的不同论坛上搜索答案,但似乎没有与我的情况相符的... 我正在使用 Windows 7,VS2010。 我有一个使用定时器来调用任务栏刷新功能的应用程序。在该任务栏函数中包含对 LoadI
我是一名优秀的程序员,十分优秀!