如何判断扩展方法是否影响“this”?

时间:2012-01-20 10:55:40

标签: c# .net extension-methods immutability

我知道String扩展方法返回一个String,并且实际上不会影响调用扩展方法的变量(因此它是不可变的) - 但是如何判断其他扩展方法是否有效?例如,我正在使用List<NewsItem> - 我需要按日期降序排序此列表,因此我编写了此代码:

newsItems.OrderByDescending(o => o.Date);

这是否会影响newsItems列表或只是返回IOrderedEnumerable ??

换句话说,如果上面的代码实际上是:

newsItems = newsItems.OrderByDescending(o => o.Date).ToList();

...

谢谢,

3 个答案:

答案 0 :(得分:4)

OrderByDescendingIEnumerable<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

上调用1}}