Перейти к основному содержимому

SerializedProperty Extensions

Запись свойств в редакторе одной строкой — и доступ к настоящему полю C#, которое свойство показывает в инспекторе.

Быстрый старт​

До — Unity APIПосле — FastTools
var manaCost = serializedObject
.FindProperty("_manaCost");

serializedObject.Update();
manaCost.intValue = 42;
serializedObject
.ApplyModifiedProperties();
var manaCost = serializedObject
.FindProperty("_manaCost");

manaCost
.Update()
.SetIntAndApply(42);

Запись значений​

До — Unity APIПосле — FastTools
manaCost.intValue = 42;
manaCost.SetInt(42);
manaCost.intValue = 42;
manaCost.serializedObject
.ApplyModifiedProperties();
manaCost.SetIntAndApply(42);
manaCost.intValue = 42;
manaCost.serializedObject
.ApplyModifiedPropertiesWithoutUndo();
manaCost
.SetIntAndApplyWithoutUndo(42);

Поддерживаемые типы​

ЗначенияСеттеры
ЧислаSetInt, SetUint, SetLong, SetUlong, SetFloat, SetDouble
Текст, bool и хэшSetString, SetBool, SetHash128
ВекторыSetVector2, SetVector2Int, SetVector3, SetVector3Int, SetVector4, SetQuaternion
ОбластиSetRect, SetRectInt, SetBounds, SetBoundsInt
Типы UnitySetColor, SetGradient, SetAnimationCurve
Идентификаторы объектовSetEntityId

У каждого есть перегрузка SetValue: SetValue(42) вызывает SetInt, поэтому тип аргумента должен совпадать с типом поля.

Перечисления, массивы и ссылки​

UnityFastTools
enumValueIndex = 1SetEnumIndex(1)
enumValueFlag = flagsSetEnumFlag(flags)
arraySize = 5SetArraySize(5)
arraySize += nAddArraySize(n = 1)
arraySize -= nRemoveArraySize(n = 1)
managedReferenceValue = valueSetManagedReference(value)
objectReferenceValue = valueSetObjectReference(value)
boxedValue = valueSetBoxed(value)
exposedReferenceValue = valueSetExposedReference(value)

Update() и Apply…()​

UnityFastTools
serializedObject.Update()Update()
serializedObject.UpdateIfRequiredOrScript()UpdateIfRequiredOrScript()
serializedObject.ApplyModifiedProperties()ApplyModifiedProperties()
serializedObject.ApplyModifiedPropertiesWithoutUndo()ApplyModifiedPropertiesWithoutUndo()

Методы вызываются прямо на свойстве и, как все сеттеры, возвращают его.

Поле C# из инспектора​

Три метода находят поле C#, которое свойство показывает в инспекторе: его тип, само поле и объект, в котором оно лежит.

public class AbilityBook : MonoBehaviour
{
[SerializeField]
private List<Ability> _abilities = new() { new Ability() };

[SerializeReference]
private IAbilityEffect _effect = new BurnEffect();
}

[Serializable]
public class Ability { public string Name = "Fireball"; }

[Serializable]
public class BurnEffect : IAbilityEffect { public float Damage = 5f; }
Путь свойстваGetPropertyType()GetFieldInfo()GetDeclaringInstance()
_abilitiesList<Ability>AbilityBook._abilitiesэкземпляр AbilityBook
_abilities[0]AbilityAbilityBook._abilitiesэкземпляр AbilityBook
_abilities[0].NamestringAbility.NameAbility с индексом 0
_effectIAbilityEffectAbilityBook._effectэкземпляр AbilityBook
_effect.DamagefloatBurnEffect.Damageэкземпляр BurnEffect
  • если поле не найдено, GetPropertyType() и GetFieldInfo() возвращают null, а GetDeclaringInstance() — только когда не найден объект-владелец;
  • методы читают только первый целевой объект и только применённые значения.
внимание

Если владелец поля — структура, GetDeclaringInstance() возвращает её boxed-копию. Изменения такой копии не попадают в оригинал; записывайте значения через SerializedProperty.

Имя поля и проверки для отрисовки​

Путь свойстваGetMemberName()IsArrayElement()HasFoldout()
_abilities[0]"_abilities"truetrue
_abilities[0].Name"Name"falsefalse
_effect"_effect"falsefalse
примечание

HasFoldout() возвращает true для обычного составного поля с видимыми вложенными полями, поэтому может не совпадать с инспектором: у поля [SerializeReference] инспектор рисует foldout, а метод возвращает false; свои PropertyDrawer метод не учитывает.

Persistent()​

Persistent() возвращает копию свойства на собственном SerializedObject: её можно использовать позже, например в EditorApplication.delayCall.

До — Unity APIПосле — FastTools
var source = manaCost.serializedObject;
var independentObject = new SerializedObject(
source.targetObjects, source.context);
var independent = independentObject
.FindProperty(manaCost.propertyPath);
var independent = manaCost.Persistent();
  • копия принадлежит вызывающему коду: освободите её вместе с её serializedObject;
  • неприменённые записи исходного свойства в копию не попадают;
  • если свойства на объектах нет, метод возвращает null.
var independent = manaCost.Persistent();
if (independent == null) return;

EditorApplication.delayCall += () =>
{
using (independent.serializedObject)
using (independent)
independent.Update().SetIntAndApply(42);
};

Пример в пакете​

В EditorTools кнопка Halve cooldown, +5 MP записывает два свойства через SetFloat и SetIntAndApply.