C# 为什么这会导致InvalidOperationException:不同步?
下面代码的目标是拥有“热键”(因为没有更好的词)。这样的热键是一个切换多个复选框的复选框 我知道当你试图在循环时更改字典时,字典会抛出一个不同步的异常。但我循环的那个只不过是被人读过而已 我已经找到了一个解决方案,但我仍然对这导致异常的原因感兴趣。C# 为什么这会导致InvalidOperationException:不同步?,c#,dictionary,unity3d,C#,Dictionary,Unity3d,下面代码的目标是拥有“热键”(因为没有更好的词)。这样的热键是一个切换多个复选框的复选框 我知道当你试图在循环时更改字典时,字典会抛出一个不同步的异常。但我循环的那个只不过是被人读过而已 我已经找到了一个解决方案,但我仍然对这导致异常的原因感兴趣。 public class JointTypeSelectDisplay { public Dictionary<JointType, bool> SelectedJoints; private Dictionary&l
public class JointTypeSelectDisplay
{
public Dictionary<JointType, bool> SelectedJoints;
private Dictionary<JointType, JointTypeListElement> _jointToggles;
private void UpdateDisplay()
{
foreach (var joint in SelectedJoints)
{
_jointToggles[joint.Key].SetState(SelectedJoints[joint.Key]);
}
}
}
public class JointTypeListElement
{
public Toggle JointToggle;
public void SetState(bool active)
{
JointToggle.isOn = active;
}
}
公共类连接类型选择显示
{
公共字典选择关节;
私人词典;
私有void UpdateDisplay()
{
foreach(选定关节中的var关节)
{
_jointToggles[joint.Key].SetState(SelectedJoints[joint.Key]);
}
}
}
公共类JointTypeListElement
{
公共开关连接;
公共无效设置状态(布尔激活)
{
JointToggle.isOn=激活;
}
}
编辑:堆栈跟踪:
InvalidOperationException:不同步
System.Collections.Generic.Dictionary的2+枚举数[Windows.Kinect.JointType,System.Boolean].VerifyState()(位于/Users/builduser/buildslave/mono运行时和classlibs/build/mcs/class/corlib/System.Collections.Generic/Dictionary.cs:912)
System.Collections.Generic.Dictionary的2+枚举数[Windows.Kinect.JointType,System.Boolean].MoveNext()(位于/Users/builduser/buildslave/mono运行时和classlibs/build/mcs/class/corlib/System.Collections.Generic/Dictionary.cs:835)
KinectFilterTesting.JointTypeSelectDisplay.UpdateDisplay()(位于Assets/Scripts/Simon/JointTypeSelectDisplay.cs:146)
KinectFilterTesting.JointTypeSelectDisplay.SetSelectedState(System.Collections.Generic.List'1类型,布尔选择)(位于Assets/Scripts/Simon/JointTypeSelectDisplay.cs:131)
KinectFilterTesting.JointTypeSelectDisplay.SetRightArm(已选择布尔值)(位于Assets/Scripts/Simon/JointTypeSelectDisplay.cs:160)
UnityEngine.Events.InvokableCall'1[System.Boolean].Invoke(System.Object[]args)(位于C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:141)
UnityEngine.Events.InvokableCallList.Invoke(System.Object[]参数)(位于C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:574)
UnityEngine.Events.UnityEventBase.Invoke(System.Object[]参数)(位于C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:716)
UnityEngine.Events.UnityEvent'1[System.Boolean].Invoke(布尔值arg0)(位于C:/buildslave/unity/build/Runtime/Export/UnityEvent_1.cs:53)
UnityEngine.UI.Toggle.Set(布尔值,布尔sendCallback)(位于C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Toggle.cs:167)
UnityEngine.UI.Toggle.Set(布尔值)(位于C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Toggle.cs:142)
UnityEngine.UI.Toggle.set_isOn(布尔值)(位于C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Toggle.cs:136)
UnityEngine.UI.Toggle.InternalToggle()(位于C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Toggle.cs:199)
UnityEngine.UI.Toggle.OnPointerClick(UnityEngine.EventSystems.PointerEventData eventData)(位于C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Toggle.cs:210)
UnityEngine.EventSystems.ExecuteEvents.Execute(IPointerClickHandler处理程序,UnityEngine.EventSystems.BaseEventData eventData)(位于C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:52)
UnityEngine.EventSystems.ExecuteEvents.ExecuteEvents[IPointerClickHandler](UnityEngine.GameObject目标,UnityEngine.EventSystems.BaseEventData事件数据,UnityEngine.EventSystems.EventFunction'1 functor)(位于C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:269)
UnityEngine.EventSystems.EventSystem:Update()
可能是另一个线程上正在修改
selectedjoint
。解决此问题的最简单方法是复制密钥并对其进行迭代:
private void UpdateDisplay()
{
List<JointType> joints = new List<JointType>(SelectedJoints.Keys);
foreach (JointType joint in joints)
{
if(_jointToggles.ContainsKey(joint) && SelectedJoints.ContainsKey(joint))
_jointToggles[joint].SetState(SelectedJoints[joint]);
}
}
private void UpdateDisplay()
{
列表关节=新列表(SelectedJoints.Keys);
foreach(接头中的接头类型接头)
{
if(_jointToggles.ContainsKey(关节)和&SelectedJoints.ContainsKey(关节))
_jointToggles[joint].SetState(选定的关节[joint]);
}
}
请注意,if条件是必需的,因为错误强烈表明在执行
UpdateDisplay
时正在修改集合。此外,这也不会捕获在UpdateDisplay
运行时将条目添加到SelectedJoints
的情况,因此如果您还没有这样做,那么更频繁地运行UpdateDisplay
可能是有意义的。为什么要使用SelectedJoints[joint.Key]
而不是joint.Value
,一定是尝试不同解决方案后留下的。不管怎样,你的建议仍然是抛出不同步的异常。我不是建议这样可以修复错误,只是好奇而已。你能包括堆栈跟踪以便我们能准确地看到异常抛出的位置吗?@juharr我已经添加了它。这里有很多特定于unity的东西。你能提供调用UpdateDisplay()
的上下文吗?以及如何更新selectedjoint
?看起来,当您将一个切换设置为“开”时,它会触发另一个事件,在第一个调用仍在迭代时更改SelectedJoints的内容。感谢您的建议。正如我提到的,我已经有了一个与您的解决方案非常相似的解决方案(我循环了SelectedJoints.Keys.ToArray()
)。至于原因,这是Kryptos在评论中建议的。也许你可以在LateUpdate()
方法中更新状态。我认为这将防止在同一帧中触发新事件(这是我使用的一种技巧)