我知道String扩展方法返回一个String,并且实际上不会影响调用扩展方法的变量(因此它是不可变的) - 但是如何判断其他扩展方法是否有效?例如,我正在使用List<NewsItem>
- 我需要按日期降序排序此列表,因此我编写了此代码:
newsItems.OrderByDescending(o => o.Date);
这是否会影响newsItems列表或只是返回IOrderedEnumerable ??
换句话说,如果上面的代码实际上是:
newsItems = newsItems.OrderByDescending(o => o.Date).ToList();
...
谢谢,
丹
答案 0 :(得分:4)
OrderByDescending
是IEnumerable<T>
上的一种扩展方法,它本身提供只读访问权限。当然,扩展方法可以强制转换到List<T>
,但基本上没有一个LINQ to Objects扩展方法会影响它们的目标(假设目标不受迭代的影响,当然)。
LINQ以功能样式设计 - 方法返回数据的新视图,而不是更改它们被调用的目标。
编辑:正如drew所述,[Pure]
属性可用作对此的指示,并且一些工具将会接收它。但是:
[Pure]
属性已正确应用[Pure]
属性并不总是很容易(例如,它没有显示在我链接到的文档中)答案 1 :(得分:2)
所有Linq扩展方法仅对序列执行查询操作,因此假设它们是只读的(查询)。因此,它们返回IEnumerable<T>
个实例,这些实例提供表示操作结果的值序列。
当然没有什么能阻止你制作一个扩展方法来修改它所应用的对象(this
)。
然而,API包含在这种情况下有用的元数据。 PureAttribute
属性可用于没有副作用的方法。如果在IDE中使用诸如ReSharper之类的工具,那么当您尝试调用纯方法并且不使用结果时它会发出警告。因为这样的方法是纯粹的,它在内存中的其他地方没有可见的副作用,因此忽略结果有点愚蠢。 Linq运算符使用此属性进行注释。所以它是object.ToString()
例如。您也可以在自己的代码上使用此属性。
tl; Dr R#在这种情况下会发现你的错误。
答案 2 :(得分:0)
通常由参数(值类型或引用类型),其次由返回类型。
如果你有一个方法签名如DateTime DateTime.AddDays(int days)
,你得到两个提示,该方法不会影响原始日期时间 - 首先,DateTime是一个值类型,其次是它返回一个DateTime。如果在方法体中修改了值类型,则只会将其更改本地应用于堆栈上的副本。除非返回值类型,否则调用者永远不会观察到这些更改。相反,参考类型可以在调用方法中修改,并且具有调用者观察到的修改。
类似地,如果您有IOrderedEnumerable<T> OrderBy(IEnumerable<T> enumerable)
之类的方法,尽管输入类型是引用类型(并且可以修改),但提示是,当返回新类型时,原始类型将保持不变。 。
最后,这可以通过测试来确认。作为一般兴趣点,LINQ方法链扩展方法都返回一个新的IEnumerable<T>
,是惰性求值的,不要修改传入的内容IEnumerable<T>
,而应用一个在{{{{}}时计算的过滤器在返回的GetEnumerator