RAII非常适合确保您不会失败的调用。通常,我会使用 class 实现。我目前正在使用Unity,并且意识到在Update(甚至在编辑器脚本中)中会产生垃圾。我当时在想,为Begin / End操作创建 struct 包装器是避免分配的好模式吗? (自value types don't allocate on the heap起。)
这是一个编辑器脚本示例:
public struct ActionOnDispose : IDisposable
{
Action m_OnDispose;
public ActionOnDispose(Action on_dispose)
{
m_OnDispose = on_dispose;
}
public void Dispose()
{
m_OnDispose();
}
}
EditorGUILayout是一种Unity类型,它公开了需要在代码前后调用的几个函数。我会像这样使用ActionOnDispose:
public static ActionOnDispose ScrollViewScope(ref Vector2 scroll)
{
scroll = EditorGUILayout.BeginScrollView(scroll);
return new ActionOnDispose(EditorGUILayout.EndScrollView);
}
private Vector2 scroll;
public void OnGUI() // called every frame
{
using (EditorHelper.ScrollViewScope(ref scroll))
{
for (int i = 0; i < 1000; ++i)
{
GUILayout.Label("Item #"+ i);
}
}
}
上面的简单示例按预期工作,并且对ScrollViewScope的每次调用都调用一次Dispose,因此它看起来是正确的。 Unity甚至提供了一个有范围的结构:EditorGUI.DisabledScope,但在许多情况下不是这样。所以我想知道这种结构是否有缺点? (我假设如果以某种方式复制了该结构,那么将丢弃旧副本,并且我的结束操作被调用了两次?我看不到这种情况,但是我对C#值类型不是很熟悉。)
编辑:我要特别询问是否使用结构(值类型)是否重要。 Is abusing IDisposable to benefit from “using” statements considered harmful讨论了IDisposable是否很好用。
答案 0 :(得分:0)
Jeroen Mostert 的评论作为答案:
<块引用>赋值不会产生垃圾,写新的 ActionOnDispose(EditorGUILayout.EndScrollView)
会。 (是的,这也会在水下分配一个新的 Action,这只是句法简写。)一般来说,如果您使用委托,很难避免分配,但这样做通常也没有回报。生命周期较短的对象在 gen 0 中收集,非常高效。我没有受过教育的猜测是,像 EditorGUILayout.BeginScrollView
这样的方法会自己分配东西,以至于在您的一端再分配一次就没有太大关系了。
回答你的另一个问题,不,复制结构不会导致方法被调用两次。做到这一点的唯一方法是实际将其包装在两个不同的 Dispose
范围内。 C#没有RAII;超出范围的事情什么都不做。真正神奇的是 using
语句。
我的结论:
我可以为我的每个用例制作 ActionOnDispose 的版本,以避免使用产生垃圾的 Action。