Unity 6.3
0 онлайн 83 гостей 3 в системе
Вход

SerializedProperty.boxedValue

Declaration

public object boxedValue;

Описание

Значение SerializedProperty, помещённое в поле System.Object.

Это свойство представляет значение SerializedProperty как System.Object, которое обворачивает базовый тип.

Это свойство облегчает написание кода, которому не нужен точный тип SerializedProperty для получения или установления его значения. Например, это свойство может получить доступ к любому числовому типу, строкам, встроенным типам, таким как Vector3 и ManagedReference объекты с одинаковым синтаксисом. Это свойство может устранить необходимость в переключающихся инструкциях или медленных альтернативах, основанных на .NET Reflection, для определения типа SerializedProperty.

Обращение типа значения в основанный на куче System.Object требует преобразования, называемого "boxing", которое добавляет нагрузку на производительность. В случаях, когда производительность важна и вы заранее знаете тип, используйте соответствующие типо-специфические доступники, такие как intValue, stringValue, или managedReferenceValue вместо этого свойства. Это удаляет нагрузку на производительность, которую требует это свойство для boxing.

Когда ваше приложение устанавливает это свойство, Unity пытается развернуть и преобразовать предоставленный System.Object в тип свойства SerializedProperty. Если это не удается, Unity возвращает ошибку InvalidCastException.

boxedValue имеет некоторые ограничения для свойств типа SerializedPropertyType.Generic:

  • Структуры и объекты, серийизованные по значениям, могут быть доступны, если они не содержат фиксированных буферов.
  • Свойство не может быть массивом или списком. Однако доступ к свойству, которое является элементом массива или списка, поддерживается.
  • Unity встроенные типы Структуры, которые категоризируются в типе Generic, не могут быть доступны. Но встроенные типы, такие как Vector3 которые имеют свою собственную позицию в перечне SerializedPropertyType перечисление работает.

Дополнительные ресурсы: ,propertyType,.

using UnityEditor;
using UnityEngine;
using System.Collections.Generic;

// To try this example save it as a script called BoxedValueStructExample.cs, // then create an asset file from the Project Window context menu, then inspect it

[System.Serializable] public struct Element { public int m_IntData; public Color m_ColorData; public Rect m_Rect;

public void Change() { ++m_IntData; m_ColorData = new Color(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f), 1); m_Rect = new Rect(Random.Range(0, 100), Random.Range(0, 100), Random.Range(0, 100), Random.Range(0, 100)); } };

[CreateAssetMenu] public class BoxedValueStructExample : ScriptableObject { public Element m_NewItem = new Element(); public List<Element> m_ItemList = new List<Element>(); }

[CustomEditor(typeof(BoxedValueStructExample)), CanEditMultipleObjects] public class BoxedValueStructExampleEditor : Editor { SerializedProperty m_NewItemProp; SerializedProperty m_ListProp;

public void OnEnable() { m_NewItemProp = serializedObject.FindProperty("m_NewItem"); m_ListProp = serializedObject.FindProperty("m_ItemList"); }

public override void OnInspectorGUI() { EditorGUILayout.PropertyField(m_NewItemProp);

GUILayout.Space(30);

if (GUILayout.Button("Add New Item to List")) { // Read full Element struct Element newItem = (Element)m_NewItemProp.boxedValue;

// Append a new item to list and set it to the same values as m_NewItem m_ListProp.arraySize++; m_ListProp.GetArrayElementAtIndex(m_ListProp.arraySize - 1).boxedValue = newItem;

// Update NewItem to some new values newItem.Change(); m_NewItemProp.boxedValue = newItem;

// Because boxedValue is used, the code above does not need to deal with fields inside the struct, // and it would not need to change as fields are added and removed to Element }

GUILayout.Space(30); EditorGUILayout.PropertyField(m_ListProp);

serializedObject.ApplyModifiedProperties(); } }
using System.Text;
using UnityEditor;
using UnityEngine;

public class BoxedValueExample { [MenuItem("Example/Log Property Values")] static void MenuCallback() { var log = new StringBuilder(); var obj = Selection.activeGameObject; { log.AppendLine($"Contents of {obj.name}"); LogProperties(obj, log); }

foreach (var comp in obj.GetComponents<Component>()) { log.AppendLine(); log.AppendLine($"Component {comp.GetType().ToString()}"); LogProperties(comp, log); }

Debug.Log(log.ToString()); }

static void LogProperties(UnityEngine.Object obj, StringBuilder log) { using (var so = new SerializedObject(obj)) { var iterator = so.GetIterator(); iterator.Next(true); // Move past root property

// Printing top level propertise only do { log.Append(iterator.name); log.Append(" type: "); log.Append(iterator.propertyType); LogValue(iterator, log); log.AppendLine(); } while (iterator.Next(false)); } }

static void LogValue(SerializedProperty serializedProperty, StringBuilder log) { // Don't attempt to print these types as strings if (serializedProperty.propertyType == SerializedPropertyType.Generic || serializedProperty.propertyType == SerializedPropertyType.ObjectReference || serializedProperty.propertyType == SerializedPropertyType.ManagedReference) { return; }

log.Append($" value: {serializedProperty.boxedValue}"); }

[MenuItem("Example/Log Property Values", true)] static bool MenuValidation() { return Selection.activeGameObject != null; } }

Это рекурсивная версия примера, с большей информацией и форматированием, но всё равно опирающаяся на boxedValue.

using System.Collections.Generic;
using System.Text;
using UnityEditor;
using UnityEngine;

public class RecursivePropertyLogExample { [MenuItem("Example/Log Property Values (Recursive)")] static void MenuCallback() { var obj = Selection.activeGameObject; { var log = new StringBuilder(); log.AppendLine($"Contents of {obj.name}"); LogProperties(obj, log);

// Log separately to avoid reaching the individual message size limit Debug.Log(log.ToString()); }

foreach (var comp in obj.GetComponents<Component>()) { var log = new StringBuilder(); log.AppendLine($"Component {comp.GetType().ToString()} of {obj.name}"); LogProperties(comp, log); Debug.Log(log.ToString()); } }

static void LogProperties(UnityEngine.Object obj, StringBuilder log) { using (var so = new SerializedObject(obj)) { var iterator = so.GetIterator(); iterator.Next(true); // Move past root property

// Prevent endless loops if SerializeReference instances form cyclical graphs var visitedManagedReferences = new HashSet<long>();

bool visitChild; do { visitChild = false;

if (iterator.propertyType == SerializedPropertyType.Generic) { visitChild = true; } else if (iterator.propertyType == SerializedPropertyType.ManagedReference) { long refId = iterator.managedReferenceId; if (visitedManagedReferences.Add(refId)) visitChild = true; // First time seeing node, so visit it }

for (int i = 0; i < iterator.depth; i++) log.Append(" ");

if (iterator.name == "data") { // If this is an array element then it is more informative to use the name exposed by // propertyPath, e.g. "data[7]" instead of "data". var stringPos = iterator.propertyPath.LastIndexOf('.'); if (stringPos > 0) log.Append(iterator.propertyPath.Substring(stringPos + 1)); else log.Append(iterator.name); } else log.Append(iterator.name);

LogType(iterator, log); LogValue(iterator, log); log.AppendLine();

// Skip past the "Array" child inside each property of type array if (iterator.isArray) iterator.Next(true); } while (iterator.Next(visitChild)); } }

static void LogType(SerializedProperty serializedProperty, StringBuilder log) { log.Append(" type: "); if (serializedProperty.propertyType == SerializedPropertyType.Integer || serializedProperty.propertyType == SerializedPropertyType.Float) log.Append(serializedProperty.numericType); else if (serializedProperty.propertyType == SerializedPropertyType.Generic && serializedProperty.isArray) log.Append("Array"); else log.Append(serializedProperty.propertyType); }

static void LogValue(SerializedProperty serializedProperty, StringBuilder log) { // use boxedValue to get and print the value as a string // There are a few special cases to improve the quality of the output

if (serializedProperty.propertyType == SerializedPropertyType.Generic || serializedProperty.propertyType == SerializedPropertyType.AnimationCurve || serializedProperty.propertyType == SerializedPropertyType.Gradient || serializedProperty.propertyType == SerializedPropertyType.LayerMask) { return; }

if (serializedProperty.propertyType == SerializedPropertyType.ObjectReference) { if (ReferenceEquals(serializedProperty.objectReferenceValue, null)) log.Append($" value: null"); else log.Append($" instanceID: {serializedProperty.objectReferenceValue.GetInstanceID()}"); } else if (serializedProperty.propertyType == SerializedPropertyType.ManagedReference) { if (ReferenceEquals(serializedProperty.managedReferenceValue, null)) log.Append($" value: null"); else log.Append($" refId: {serializedProperty.managedReferenceId} ({serializedProperty.managedReferenceFullTypename})"); } else { log.Append($" value: {serializedProperty.boxedValue.ToString()}"); } }

[MenuItem("Example/Log Property Values (Recursive)", true)] static bool ValidateMenuItem() { return Selection.activeGameObject != null; } }