我觉得ReSharper骗我。
我有这个扩展方法(希望)返回两个枚举的xor:
public static IEnumerable<T> Xor<T>(this IEnumerable<T> first, IEnumerable<T> second)
{
lock (first)
{
lock (second)
{
var firstAsList = first.ToList();
var secondAsList = second.ToList();
return firstAsList.Except(secondAsList).Union(secondAsList.Except(firstAsList));
}
}
}
ReSharper认为我正在对两个参数执行IEnumerable的多重枚举。如果我取下锁,那么我很满意,我不会。
ReSharper是对还是错?我认为这是错的。
编辑:我确实意识到我多次枚举这些列表,但ReSharper说我多次枚举原始参数 ,我不认为这是真的。我将两个参数枚举到一个列表中,这样我就可以执行实际的集合操作,但正如我所看到的,我实际上并没有迭代多次传递的参数。
例如,如果传递的参数实际上是查询结果,我相信这种方法不会导致设置操作执行查询风暴。我通过警告多个枚举来理解ReSharper的含义:如果传递的枚举数很多,那么如果它们被多次枚举,那么对它们执行多次枚举将会慢得多。
此外,删除锁定肯定使ReSharper更快乐:
答案 0 :(得分:2)
您确实多次枚举这两个列表。您没有枚举多次作为参数传递的枚举。对于Except
的每次调用,都会枚举两次列表。对Union
的调用不会在额外的时间内枚举任何一个序列,而是枚举两次调用Except
的结果。
当然,在这样的上下文中多次迭代List
并不是真正的问题;多次迭代不变的列表不会产生负面影响。
lock
语句与序列的枚举没有任何关系。锁定IEnumerable
不会迭代它。当然,锁定这样的两个对象,特别是两个不限于此部分代码范围的对象,非常是危险的。如果其他地方的代码(例如此方法的另一个调用)最终以相反的顺序对相同的对象进行锁定,则很可能最终使用此庄园中使用的锁来解锁程序。
答案 1 :(得分:1)
这有点滑稽。
首先要做的事情是:正如您已经正确识别的那样,R#正在针对 List
的多次使用提高此检查 - 有当然,无需担心多次枚举List
- 而是反对(R'认为多次使用) IEnumerable
参数。我假设你已经知道为什么这可能会很糟糕,所以我会跳过它。
现在谈谈R#是否适合在这里抱怨。引用C#规范,
表单的锁定声明
lock (x) ...
其中
x
是引用类型的表达式,是精确的 等效到System.Threading.Monitor.Enter(x); try { ... } finally { System.Threading.Monitor.Exit(x); }
除了
x
仅评估一次。
(我已经强调了这一点,因为我喜欢这个措辞;它避免了关于这是否是“合成糖”的辩论(我绝对没有资格进入)。)
以一个产生这种R#检验的最小例子:
private static void Method(IEnumerable<int> enumerable)
{
lock (enumerable)
{
var list = enumerable.ToList();
}
}
并将其替换为我认为的规格所强制的精确等效版本:
private static void Method(IEnumerable<int> enumerable)
{
var x = enumerable;
System.Threading.Monitor.Enter(x);
try
{
var list = enumerable.ToList();
}
finally
{
System.Threading.Monitor.Exit(x);
}
}
也生成检查。
那么问题是:R#正确来产生这种检查吗?这就是我认为我们进入灰色地带的地方。当我将以下可枚举传递给这些方法中的任何一个时:
static IEnumerable<int> MyEnumerable()
{
Console.WriteLine("Enumerable enumerated");
yield return 1;
yield return 2;
}
不乘以枚举,这表明R#在此处发出警告是错误的;但是,我实际上无法在文档中找到保证 lock
或Monitor.Enter
的此行为。所以对我而言,它并不像this R# bug I reported, where use of GetType
flagged this inspection那么明确;但是我猜你是安全的。
如果你提出这个on the R# bug tracker,你可以让JetBrains最好看看a)这种行为是否确实得到保证。 b)R#是否可以调整为不警告,或提供警告的理由。
那说,当然,在这里使用锁定可能实际上并没有实现你想要实现的目标,正如其他答案和评论所述......