Resharper-unity: Debugging SerializedObject/SerializedProperty

Created on 27 Nov 2018  路  4Comments  路  Source: JetBrains/resharper-unity

Unity's main way of writing editor code that interacts with serialized objects (either in-game or assets) is the SerializedObject API. When you attach the debugger to some of this code and try to expand a SerializedProperty, things get really slow:
image

You also get some pretty interesting exceptions logged in Unity after you stop debugging:

ThreadAbortException
JetBrains.Util.Threading.ByteBufferAsyncProcessor.Put (System.Byte* start, System.Int32 count) (at <f675ed20b25e482998dbe77607068ec9>:0)
JetBrains.Util.Threading.ByteBufferAsyncProcessor.Put (JetBrains.Util.PersistentMap.UnsafeWriter+Cookie data) (at <f675ed20b25e482998dbe77607068ec9>:0)
JetBrains.Platform.RdFramework.Impl.SocketWire+Base.SendPkg (JetBrains.Util.PersistentMap.UnsafeWriter+Cookie cookie) (at <f675ed20b25e482998dbe77607068ec9>:0)
JetBrains.Platform.RdFramework.WireBase.Send (JetBrains.Platform.RdFramework.RdId id, System.Action`1[T] writer) (at <f675ed20b25e482998dbe77607068ec9>:0)
JetBrains.Platform.RdFramework.Base.ExtWire.Send (JetBrains.Platform.RdFramework.RdId id, System.Action`1[T] writer) (at <f675ed20b25e482998dbe77607068ec9>:0)
JetBrains.Platform.RdFramework.Impl.RdSignal`1[T].Fire (T value) (at <f675ed20b25e482998dbe77607068ec9>:0)
JetBrains.Rider.Unity.Editor.UnityEventLogSender+<>c__DisplayClass2_0.<SendLogEvent>b__0 () (at <f675ed20b25e482998dbe77607068ec9>:0)
JetBrains.Rider.Unity.Editor.MainThreadDispatcher.Queue (System.Action action) (at <f675ed20b25e482998dbe77607068ec9>:0)
JetBrains.Rider.Unity.Editor.UnityEventLogSender.SendLogEvent (JetBrains.Platform.Unity.EditorPluginModel.RdLogEvent logEvent) (at <f675ed20b25e482998dbe77607068ec9>:0)
JetBrains.Rider.Unity.Editor.UnityEventLogSender.ProcessQueue (JetBrains.Rider.Unity.Editor.UnityEventCollector collector) (at <f675ed20b25e482998dbe77607068ec9>:0)
JetBrains.Rider.Unity.Editor.UnityEventLogSender.<.ctor>b__0_0 (System.Object col, System.EventArgs _) (at <f675ed20b25e482998dbe77607068ec9>:0)
JetBrains.Rider.Unity.Editor.UnityEventCollector.OnAddEvent (System.EventArgs e) (at <f675ed20b25e482998dbe77607068ec9>:0)
JetBrains.Rider.Unity.Editor.UnityEventCollector+<>c__DisplayClass3_0.<ApplicationOnLogMessageReceived>b__0 () (at <f675ed20b25e482998dbe77607068ec9>:0)
JetBrains.Rider.Unity.Editor.MainThreadDispatcher.Queue (System.Action action) (at <f675ed20b25e482998dbe77607068ec9>:0)
JetBrains.Rider.Unity.Editor.UnityEventCollector.ApplicationOnLogMessageReceived (System.String message, System.String stackTrace, UnityEngine.LogType type) (at <f675ed20b25e482998dbe77607068ec9>:0)
UnityEngine.Application.CallLogCallback (System.String logString, System.String stackTrace, UnityEngine.LogType type, System.Boolean invokedOnMainThread) (at C:/buildslave/unity/build/Runtime/Export/Application.cs:127)
UnityEditor.SerializedProperty:get_arrayElementType(SerializedProperty)
Mesmer.StoreArticlesDrawer:OnGUI(Rect, SerializedProperty) (at Assets/Scripts/Mesmer/Editor/StoreArticlesDrawer.cs:65)
Mesmer.PropertyHandlers.StoreArticlesPropHandler:DrawSelf(Rect, SerializedProperty) (at Assets/Scripts/FolderInspectors/PropertyHandlers.cs:253)
Mesmer.PropertyHandlers.PropHandler:Draw(Rect, SerializedProperty, Int32) (at Assets/Scripts/FolderInspectors/PropertyHandlers.cs:38)
Mesmer.LiteralConceptInspector`1:DrawAllLiteralConcepts(Single, Single, Single, RectOffset, Int32, RectOffset, Single, Rect&, Int32&) (at Assets/Scripts/FolderInspectors/LiteralConceptInspector.cs:518)
Mesmer.LiteralConceptInspector`1:OnInspectorGUI() (at Assets/Scripts/FolderInspectors/LiteralConceptInspector.cs:272)
ObjectInspectorInitiator:OnInspectorGUI()
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)

followed by:

Invalid property to get array Element
UnityEditor.SerializedProperty:get_arrayElementType(SerializedProperty)
Mesmer.StoreArticlesDrawer:OnGUI(Rect, SerializedProperty) (at Assets/Scripts/Mesmer/Editor/StoreArticlesDrawer.cs:65)
Mesmer.PropertyHandlers.StoreArticlesPropHandler:DrawSelf(Rect, SerializedProperty) (at Assets/Scripts/FolderInspectors/PropertyHandlers.cs:253)
Mesmer.PropertyHandlers.PropHandler:Draw(Rect, SerializedProperty, Int32) (at Assets/Scripts/FolderInspectors/PropertyHandlers.cs:38)
Mesmer.LiteralConceptInspector`1:DrawAllLiteralConcepts(Single, Single, Single, RectOffset, Int32, RectOffset, Single, Rect&, Int32&) (at Assets/Scripts/FolderInspectors/LiteralConceptInspector.cs:518)
Mesmer.LiteralConceptInspector`1:OnInspectorGUI() (at Assets/Scripts/FolderInspectors/LiteralConceptInspector.cs:272)
ObjectInspectorInitiator:OnInspectorGUI()
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)

That repeats a bunch of times; one ThreadAbortException and one Invalid property error for every one of those "Timed out within 1000 ms" messages.

What's happening here is that SerializedProperty is a strange beast - it's got a field for every possible kind of data it can contain, and a "propertyType" field that tells you what data it contains. If you try to access a field of the wrong type, you get an error message. For example, trying to get the objectReferenceValue of something that's not an object reference causes:

type is not a supported pptr value
UnityEditor.SerializedProperty:get_objectReferenceValue(SerializedProperty)

This isn't an exception, though. As usual, Unity's not throwing exceptions, they're printing error messages and then doing something... undefined? As a side-effect of all of this, expanding a SerializedProperty causes Rider to hang for 10-20 seconds and tons of errors to be puked into Unity's console.

The result of this is that the debugger becomes a huge pain around SerializedObject/Property.

I'm guessing that this is a special enough case that this has to be handled by the plugin rather than a general Rider fix, which is why I'm creating this as an issue rather than filing a normal bug report in Rider. If the debugger knows about the SerializedProperty type, it could avoid trying to get at the properties it shouldn't touch by checking the value of PropertyType. I have no idea how much the plugin can influence the debugger, though.

There might be alternative solutions?

debugger

Most helpful comment

Put this on a GameObject, attach the debugger:

```cs
using UnityEngine;

if UNITY_EDITOR

using UnityEditor;

endif

public class TestScript : MonoBehaviour {
public string s1;
}

if UNITY_EDITOR

[CustomEditor(typeof(TestScript))]
public class TestScriptEditor : Editor {

private SerializedProperty s1;

void OnEnable() {
    s1 = serializedObject.FindProperty("s1");
}

public override void OnInspectorGUI() {
    // Attach to the next line, try to fold out "s1" under "variables"
    EditorGUILayout.PropertyField(s1);
    serializedObject.ApplyModifiedProperties();
}

}

endif

```cs

All 4 comments

Looks like an interesting use case! I think the ideal case would be that SerializedProperty had a [DebuggerTypeProxy] attribute applied that could specify a type that provides the debugger with a specialised view. We have talked about a couple of possibilities for how plugins can influence the debugger by "adding" attributes to already compiled code, or being able to filter the values listed and evaluated, and we have some existing ideas on how to use this (e.g. hiding the obsolete members of MonoBehaviour), I think we'll add this to the list.

Would you be able to come up with a super simple repro so we can take a look, please?

// cc @ArsenyChernyaev

Put this on a GameObject, attach the debugger:

```cs
using UnityEngine;

if UNITY_EDITOR

using UnityEditor;

endif

public class TestScript : MonoBehaviour {
public string s1;
}

if UNITY_EDITOR

[CustomEditor(typeof(TestScript))]
public class TestScriptEditor : Editor {

private SerializedProperty s1;

void OnEnable() {
    s1 = serializedObject.FindProperty("s1");
}

public override void OnInspectorGUI() {
    // Attach to the next line, try to fold out "s1" under "variables"
    EditorGUILayout.PropertyField(s1);
    serializedObject.ApplyModifiedProperties();
}

}

endif

```cs

See also RIDER-37068

No longer seems to be an issue with Rider 2020.1.2.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

RealMSHB picture RealMSHB  路  3Comments

Strepto picture Strepto  路  4Comments

citizenmatt picture citizenmatt  路  5Comments

AmazingThew picture AmazingThew  路  4Comments

justinlueders picture justinlueders  路  5Comments