Move to next property.
Update the SerializedProperty so that it points to the next property, in the order of serialization.
This is can be used to traverse the state of objects without prior knowledge of their data structures. It is also an efficient way to iterate through arrays.
If the current property is a compound type, such as an struct, array, string, or inline Unity struct such as Vector3, then the enterChildren
parameter determines whether to either visit the nested properties or to skip to the property immediately after the compound type.
Next will never move to a different Object, so when the current property is of type SerializedPropertyType.ObjectReference then calling Next(true)
will not visit the properties of that referenced object. One way to visit a referenced object is to retrieve the object with
SerializedProperty.objectReferenceValue and construct a new SerializedObject instance for that target.
If there are no further properties in the SerializedObject, this method will return false, and the SerializedProperty is set to an invalid state that
not longer references a property.
using System; using System.Collections.Generic; using System.Text; using UnityEngine; using UnityEditor;
public class SerializePropertyNextExample : ScriptableObject { public long m_dataFirst = 45; public string m_data2 = "hi";
[Serializable] class NestedInline { public long[] m_data3 = new long[] {1, 2}; public bool m_data4 = true; } [SerializeField] NestedInline m_nested;
[MenuItem("Example/SerializedProperty Next Example")] static void NextExample() { var scriptableObject = ScriptableObject.CreateInstance<SerializePropertyNextExample>();
using (var serializedObject = new SerializedObject(scriptableObject)) { var sb = new StringBuilder();
// Visit the top level (depth 0) properties: m_dataFirst, m_data2 and m_nested VisitAll(serializedObject, false, sb);
// Visit each property, down to the granularity of individual string and array elements VisitAll(serializedObject, true, sb); Debug.Log(sb.ToString()); } }
static void VisitAll(SerializedObject serializedObject, bool visitChildren, StringBuilder report) { report.AppendLine($"Traversal result (visitChildren: {visitChildren})");
// Start at the first field, instead of using GetIterator(), in order to skip past the internal properties var serializedProperty = serializedObject.FindProperty("m_dataFirst"); do { report.AppendLine($"\tFound {serializedProperty.propertyPath} (depth {serializedProperty.depth})"); } while (serializedProperty.Next(visitChildren)); } }
using System; using System.Text; using UnityEngine; using UnityEditor;
public class SerializePropertyArrayEnumerationWithNextExample : ScriptableObject { // Example of enumerating the elements of an array of struct using Next() [Serializable] public struct Data { public int m_Data1; public string m_Data2; }
public Data[] m_Data; public bool m_BeyondData;
[MenuItem("Example/SerializedProperty Array Enumeration Using Next")] static void TestArrayEnumeration() { var scriptableObject = ScriptableObject.CreateInstance<SerializePropertyArrayEnumerationWithNextExample>(); scriptableObject.m_Data = new Data[] { new Data() { m_Data1 = 0, m_Data2 = "zero" }, new Data() { m_Data1 = 1, m_Data2 = "one" }, new Data() { m_Data1 = 2, m_Data2 = "two" } };
var report = new StringBuilder();
using (var serializedObject = new SerializedObject(scriptableObject)) { var arrayProperty = serializedObject.FindProperty("m_Data");
var arrayElement = arrayProperty.GetArrayElementAtIndex(0); var arraySize = arrayProperty.arraySize;
for (int i = 0; i < arraySize; i++) { ReportElement(arrayElement, i, report); arrayElement.Next(false); } } Debug.Log(report.ToString()); }
static void ReportElement(SerializedProperty arrayElement, int index, StringBuilder report) { var data1 = arrayElement.FindPropertyRelative("m_Data1").intValue; var data2 = arrayElement.FindPropertyRelative("m_Data2").stringValue; report.AppendLine($"Visiting Index {index}: {data1}, {data2}"); } }
If a SerializedProperty is referencing a ManagedReference, e.g. a field with the SerializeReference attribute, and Next is called with enterChildren set to true, then the SerializedProperty will move to the first property inside the managed object. Because managed references can form cyclical graphs, calling Next(true) blindly could potentially cause an endless loop. The following example demonstrates a technique to avoid that.
using System; using System.Collections.Generic; using System.Text; using UnityEngine; using UnityEditor;
[CreateAssetMenu] public class SerializePropertyNextSerializeReferenceExample : ScriptableObject { [Serializable] public class Node { public int m_Data; public string m_Data2;
[SerializeReference] public Node m_Child1 = null;
[SerializeReference] public Node m_Child2 = null; }
[SerializeReference] public Node m_Front = null;
[MenuItem("Example/SerializedProperty Next Cyclic Graph Example")] static void TestNextOnCyclicGraph() { var scriptableObject = ScriptableObject.CreateInstance<SerializePropertyNextSerializeReferenceExample>();
// Setup a graph of 3 nodes that has several cycles scriptableObject.m_Front = new Node() { m_Data = 1, m_Data2 = "First Node" };
var node2 = new Node() { m_Data = 2, m_Data2 = "Second Node", m_Child1 = scriptableObject.m_Front }; scriptableObject.m_Front.m_Child1 = node2;
var node3 = new Node() { m_Data = 3, m_Data2 = "Third Node" }; scriptableObject.m_Front.m_Child2 = node3; node2.m_Child2 = node3; node3.m_Child1 = scriptableObject.m_Front;
using (var serializedObject = new SerializedObject(scriptableObject)) { var serializedProperty = serializedObject.FindProperty("m_Front");
var sb = new StringBuilder(); sb.AppendLine("Graph traversal result:");
// Track visited Node objects by managed reference id to prevent endless looping var visitedNodes = new HashSet<long>();
bool visitChild; do { // default is false so we don't enumerate each character of each string, visitChild = false;
if (serializedProperty.propertyType == SerializedPropertyType.ManagedReference) { long refId = serializedProperty.managedReferenceId; if (visitedNodes.Add(refId)) visitChild = true; // First time seeing node, so visit it } else if (serializedProperty.propertyType == SerializedPropertyType.String) { sb.AppendLine($"Found {serializedProperty.propertyPath} : {serializedProperty.stringValue}"); } else if (serializedProperty.propertyType == SerializedPropertyType.Integer) { sb.AppendLine($"Found {serializedProperty.propertyPath} : {serializedProperty.intValue}"); } } while (serializedProperty.Next(visitChild));
/*Expected output Graph traversal result: Found m_Front.m_Data : 1 Found m_Front.m_Data2 : First Node Found m_Front.m_Child1.m_Data : 2 Found m_Front.m_Child1.m_Data2 : Second Node Found m_Front.m_Child1.m_Child2.m_Data : 3 Found m_Front.m_Child1.m_Child2.m_Data2 : Third Node */ Debug.Log(sb.ToString()); } } }
Additional resources: NextVisible, hasChildren, Reset, depth, SerializedObject.GetIterator, GetEndProperty.
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thank you for helping to make the Unity documentation better!
Your feedback has been submitted as a ticket for our documentation team to review.
We are not able to reply to every ticket submitted.