c# - 同步集合 : ReSharper "Implicitly captured closure"

标签 c# collections closures resharper

我实现了这个扩展方法来同步一个集合与另一个不同类型的集合:

public static void Synchronize<TFirst, TSecond>(
    this ICollection<TFirst> first,
    IEnumerable<TSecond> second,
    Func<TFirst, TSecond, bool> match,
    Func<TSecond, TFirst> create)
{
    var secondCollection = second.ToArray();

    var toAdd = secondCollection.Where(item => !first.Any(x => match(x, item))).Select(create);

    foreach (var item in toAdd)
    {
        first.Add(item);
    }

    var toRemove = first.Where(item => !secondCollection.Any(x => match(item, x))).ToArray();

    foreach (var item in toRemove)
    {
        first.Remove(item);
    }
}

ReSharper 给我两个“隐式捕获闭包”,一个在第一个 Where 上,一个在第二个上,有没有办法修复它?我找不到。

[更新]

根据 Eric 的观察,我写了一个比使用 equals 函数的版本更快的版本,使用哈希代替:

public static void Synchronize<TFirst, TSecond>(
    this ICollection<TFirst> first,
    IEnumerable<TSecond> second,
    Func<TSecond, TFirst> convert,
    Func<TFirst, int> firstHash = null,
    Func<TSecond, int> secondHash = null)
{
    if (firstHash == null)
    {
        firstHash = x => x.GetHashCode();
    }

    if (secondHash == null)
    {
        secondHash = x => x.GetHashCode();
    }

    var firstCollection = first.ToDictionary(x => firstHash(x), x => x);
    var secondCollection = second.ToDictionary(x => secondHash(x), x => x);

    var toAdd = secondCollection.Where(item => firstCollection.All(x => x.Key != item.Key)).Select(x => convert(x.Value));

    foreach (var item in toAdd)
    {
        first.Add(item);
    }

    var toRemove = firstCollection.Where(item => secondCollection.All(x => x.Key != item.Key));

    foreach (var item in toRemove)
    {
        first.Remove(item.Value);
    }
}

最佳答案

首先让我描述一下 Resharper 试图提醒您注意的问题。假设你有:

Action M(Expensive expensive, Cheap cheap)
{
    Action shortLived = ()=>{DoSomething(expensive);};
    DoSomethingElse(shortLived);
    Action longLived = ()=>{DoAnotherThing(cheap);};
    return longLived;
}

这里的问题是,在 C#(以及 VB、JScript 和许多其他语言)中,两者 便宜昂贵 的生命周期被扩展以匹配 both shortLivedlongLived 的生命周期。所以即使 longLived 不使用 expensive,昂贵的资源也不会被垃圾回收,直到 longLived 结束。

你的程序匹配这个模式;您从两个 lambda 表达式中创建了两个代表;其中一个使用 first 而另一个不使用。因此,first 将在两个代表中的时间较长时存活。

其次,让我在这里批评一下 Resharper。这显然是误报。为了使其成为真正的积极因素,其中一位代表必须长寿。在这种情况下,当方法返回时,两个委托(delegate)都有资格被收集;两者都是短暂的,因此这里没有实际的错误。 Resharper 可以跟踪 Where 返回的查询对象,并注意到它们无法在该方法中存活。

第三,你应该怎么办?我会倾向于对此无所作为;如果代码按您喜欢的方式运行,则继续运行。我不会担心 Resharper 警告;我会非常非常担心这样一个事实,即您的代码对于大型集合而言效率极低。如果这两个集合有 n 和 m 个项目,那么这个程序执行 O(nm) 操作。

关于c# - 同步集合 : ReSharper "Implicitly captured closure",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17091375/

相关文章:

c# - Math.Sin 给了我奇怪的值(value)观

java - 赋值语句不起作用

javascript - 如何将 JS 对象集合发送到 ASP.NET API 服务?

function - 'closure' 和 'lambda' 之间有什么区别?

c# - 如何读取具有命名空间的 XPathDocument

c# - 访问另一个线程中的方法返回的值

vb.net - 如何将字典(集合)对象写入文件(VB .Net 2010)

php - Laravel闭包,什么是$query,$query是如何传递的?

python - 全局变量的实现与取消引用的变量

c# - 将此方法从递归转换为迭代