如何判断扩展方法是否影响'this'关键字?

4
我知道String扩展方法返回一个String并且不会影响调用该扩展方法的变量(因此它是不可变的)- 但是我怎么知道其他扩展方法是否也是这样的呢?例如,我正在使用一个List<NewsItem> - 我需要按日期降序对该列表进行排序,所以我编写了以下代码:
newsItems.OrderByDescending(o => o.Date);

这会影响newsItems列表还是仅仅返回IOrderedEnumerable结果?

换句话说,上面的代码实际上应该这样写:

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

??

Thanks,

Dan


你其实可以自己测试一下的,你知道吗...只需将3个数字放入列表中,看看它们是否被排序即可。 - Tudor
我的问题是你怎么知道?每次想知道扩展方法是否具有此效果都运行这样的测试似乎是不必要的。 - user1017882
字符串扩展方法无法更改字符串,因为字符串是不可变的。 - Drew Noakes
我知道,我在原帖中提到过。为什么有人投票关闭这个问题? - user1017882
3个回答

4

OrderByDescending是一个扩展方法,适用于IEnumerable<T>,该接口本身提供了只读访问。当然,这个扩展方法可能会进行转换到List<T>,但基本上LINQ to Objects扩展方法不会影响它们的目标对象(假设目标对象不受迭代的影响,当然)。

LINQ是按照函数式风格设计的 - 方法返回数据的新视图,而不是改变调用它们的目标对象。

编辑:如drew所述,可以使用[Pure]属性作为指示,一些工具会注意到它。然而:

  • 你仍然需要相信正确地应用了[Pure]属性
  • 很难判断是否有[Pure]属性(例如,在我链接的文档中看不到它)
  • 如果你对方法的功能不够自信,最好阅读相关文档

谢谢Jon。我现在了解了关于字符串的知识,也了解了LINQ扩展 - 这只是经验的问题(知道扩展对其目标产生什么影响和不影响)还是有一种方法可以查看扩展方法以便能够判断? - user1017882
1
@DanielMcNulty:你需要仔细阅读文档,因为在扩展方法中并没有任何不同于其他方法的地方。如果你要调用某个方法,你应该理解它将会执行什么操作,而这通常需要阅读文档。 - Jon Skeet
非常感谢Jon,这就是我想要的 - 一些澄清,是否只是通过经验和文档知道我正在使用的内容 - 这是合理的。再次感谢。 - user1017882
@JonSkeet,Daniel所问的可以通过正确的工具和PureAttribute(在我的回答中有解释)实现。 - Drew Noakes
@DrewNoakes:在某些情况下,这是可以确定的,但并不总是显而易见的,并且即使可以应用,也不总是会被应用。我会进行编辑。 - Jon Skeet

2
所有的Linq扩展方法只对序列执行查询操作,因此假设它们是只读的(查询)。因此,它们返回IEnumerable<T>实例,提供代表操作结果的值序列。
当然,你可以创建一个修改所应用对象(this)的扩展方法。
在这种情况下,API包含有用的元数据。 PureAttribute属性可用于没有副作用的方法。如果您在IDE中使用ReSharper等工具,则当您尝试调用纯方法并且不使用结果时,它将警告您。因为这样的方法是纯的,在内存中没有其他可见的副作用,因此忽略结果有点愚蠢。Linq运算符带有此属性。例如,object.ToString()。您还可以在自己的代码中使用此属性。
简而言之,R#会在这种情况下找到您的错误。

0

通常通过参数(值类型或引用类型)和返回类型来确定。

如果您有一个方法签名,例如DateTime DateTime.AddDays(int days),则会得到两个提示:该方法不会影响原始日期时间 - 首先DateTime是值类型,其次它返回一个DateTime。如果在方法体中修改值类型,则只会将更改应用于堆栈上的副本。除非返回值类型,否则调用者永远无法观察这些更改。相比之下,引用类型可以在调用方法中进行修改,并且调用者可以观察到修改。

同样,如果您有一个方法,例如IOrderedEnumerable<T> OrderBy(IEnumerable<T> enumerable),尽管输入类型是引用类型(可以被修改),但提示是返回新类型,原始类型将保持不变。

最后,可以通过测试来确认这一点。作为一个有趣的一般性观点,LINQ方法链扩展方法都返回一个新的IEnumerable<T>,是惰性评估的,并且不修改传入的IEnumerable<T>内容,而是应用一个过滤器,该过滤器在调用返回的IEnumerable<T>上的GetEnumerator时进行评估。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接