gpt4 book ai didi

c# - 你如何安全地枚举一个 List 而没有终结器妨碍?

转载 作者:行者123 更新时间:2023-11-30 18:11:38 29 4
gpt4 key购买 nike

我的应用程序中有一个 WeakReference 的静态列表。在某个时候,我想拍摄此列表中所有当前“事件”对象的快照。

代码是这样的:

private static readonly List<WeakReference> myObjects = new List<WeakReference>();

public static MyObject[] CollectObjects()
{
var list = new List<MyObject>();
foreach (var item in myObjects)
{
if (!item.IsAlive)
continue;
var obj = item.Target as MyObject;
list.Add(obj);
}
return list.ToArray();
}

我遇到的问题是有时(很少)在上面的 foreach 循环中出现“集合已修改”异常。我只在 MyObject 构造函数/终结器中从这个列表中添加/删除,它看起来像这样:

public class MyObject
{
private static readonly object _lockObject = new object();
WeakReference referenceToThis;
public MyObject()
{
lock (_lockObject)
{
referenceToThis = new WeakReference(this);
myObjects.Add(referenceToThis);
}
}
~MyObject()
{
lock (_lockObject)
{
myObjects.Remove(referenceToThis);
}
}
}

由于我的代码中没有任何其他内容触及列表,因此我假设垃圾收集器正在完成其中一些对象,就像我尝试枚举列表一样。

我考虑过在 foreach 循环周围添加一个 lock (_lockObject) 但我不确定这样的锁会如何影响 GC?

是否有更好/正确/更安全的方法来枚举弱引用列表?

最佳答案

终结器在整个垃圾回收机制中引入了显着的开销,因此最好尽可能避免使用它。在您的情况下,您可以避免它并大大简化您的设计。

不是让你的对象通过终结器检测自己的终结并将自己从该列表中删除,而是替换你的 List<WeakReference<T>>WeakCollection<T> .

WeakCollection<T>是一个集合,而不是一个列表。永远不要在集合就足够的地方使用列表。

WeakCollection<T>完全封装了它包含弱引用的事实,这意味着您将它用作常规列表,其接口(interface)中没有任何关于弱引用的内容。

WeakCollection<T>当它检测到它们已经过期时,自动从自身中删除弱引用。 (您会发现将其实现为列表比将其实现为集合要复杂得多,所以再说一遍——永远不要在集合就足够的地方使用列表。)

这是一个 WeakCollection<T> 的示例实现.当心:我还没有测试过。

namespace Whatever
{
using Sys = System;
using Legacy = System.Collections;
using Collections = System.Collections.Generic;

public class WeakCollection<T> : Collections.ICollection<T> where T : class
{
private readonly Collections.List<Sys.WeakReference<T>> list = new Collections.List<Sys.WeakReference<T>>();

public void Add( T item ) => list.Add( new Sys.WeakReference<T>( item ) );
public void Clear() => list.Clear();
public int Count => list.Count;
public bool IsReadOnly => false;
Legacy.IEnumerator Legacy.IEnumerable.GetEnumerator() => GetEnumerator();

public bool Contains( T item )
{
foreach( var element in this )
if( Equals( element, item ) )
return true;
return false;
}

public void CopyTo( T[] array, int arrayIndex )
{
foreach( var element in this )
array[arrayIndex++] = element;
}

public bool Remove( T item )
{
for( int i = 0; i < list.Count; i++ )
{
if( !list[i].TryGetTarget( out T target ) )
continue;
if( Equals( target, item ) )
{
list.RemoveAt( i );
return true;
}
}
return false;
}

public Collections.IEnumerator<T> GetEnumerator()
{
for( int i = list.Count - 1; i >= 0; i-- )
{
if( !list[i].TryGetTarget( out T element ) )
{
list.RemoveAt( i );
continue;
}
yield return element;
}
}
}
}

关于c# - 你如何安全地枚举一个 List<Weakreference> 而没有终结器妨碍?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57355009/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com