我有一个像这样定义的类(显示相关方法):
class ShaderProgram : IDisposable
{
private HashSet<Shader> _shaders = new HashSet<Shader>();
public void AttachShader(Shader shader)
{
GL.AttachShader(Handle, shader.Handle);
_shaders.Add(shader);
}
public void DetachShader(Shader shader)
{
GL.DetachShader(Handle, shader.Handle);
_shaders.Remove(shader);
}
}
现在我想弄清楚如何编写Dispose
方法,我想我可以这样做:
public void Dispose()
{
foreach(var shader in _shaders)
DetachShader(shader);
GL.DeleteProgram(Handle);
}
但现在我怀疑这是不安全的,因为我正在迭代一个集合并同时从它中删除...如果它是一个队列或堆栈Id只是说“虽然不是空的,弹出一个并删除它” ,但因为它是一个HashSet ......我不确定最好的方法是什么。我该怎么办呢?
编辑:重点是避免代码重复;我想为每个元素调用ShaderProgram.DetachShader
。我知道我可以重复该函数内的代码,然后在最后清除整个集合 - 这不是我想要做的。
现在发生在我身上,我根本不需要清空HashSet,是吗?无论如何,ShaderProgram
对象即将被销毁,我需要做的就是清理所有非托管资源,而C#GC可以清理其余的资源,对吗?
public void Dispose()
{
foreach (var shader in _shaders)
GL.DetachShader(Handle, shader.Handle);
GL.DeleteProgram(Handle);
}
那就是说,我仍然想要回答原来的问题。我的目标不是解决一个非常简单的问题,而是要学习解决这类问题的最佳方法。
答案 0 :(得分:2)
一些LINQ怎么样:
while (_shaders.Any()) {
DetachShader(_shaders.First());
}
但这通常不起作用,因为你最终可能会多次在同一个元素上调用该函数。只有函数从底层集合中删除元素才有意义。
在一般情况下,函数不修改集合,您可以使用以下内容:
while (hashset.Any()) {
var item = hashset.First();
Process(item);
hashset.Remove(item);
}
或者这个:
foreach (var item in hashset) {
Process(item);
}
hashset.Clear();
更新:正如@SLaks在评论中所指出的,为哈希集中的每个元素调用First()
,因为它被清空是O(n ^ 2)。这对于微小的收藏来说并不重要,但如果你有大量的收藏品,它可能会让世界变得不同。
答案 1 :(得分:2)
这样做没有问题,但也许您应该考虑迭代您的设置,将您的着色器从GL变量中分离,然后清除您的HashSet。如果您不想复制自己的分离方法中的代码,则应将其拆分并从这两个地方调用。
答案 2 :(得分:1)
我不明白为什么有17k声望的人会问这个问题。我错过了什么吗?
public void Dispose()
{
foreach(var shader in _shaders)
GL.DetachShader( Handle, shader.Handle );
_shaders.Clear();
}
答案 3 :(得分:1)
如果您的收藏非常小,我会使用:
foreach (var item in set.ToArray())
set.Remove(item);
另一种解决方案是RemoveWhere()
方法:
set.RemoveWhere(item =>
{
Console.WriteLine(item);
return true;
});