Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
12 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
23
Question by capnbishop · Apr 13, 2010 at 04:19 AM · serializablefieldpropertyexpose

How do I expose class properties (not fields) in C#?

Is it possible to expose properties (as opposed to fields) of a custom class to the Unity editor?

The fields of a custom class can be exposed to the editor by adding a System.Serializable attribute (this is implicit in JavaScript, but not so in C#). This is documented here. However, I have noticed that this only works for fields, but not properties.

For example:

using UnityEngine; using System.Collections;

public class NewBehaviourScript : MonoBehaviour { public Test test = new Test(); }

[System.Serializable] public class Test { public int publicField = 5; private int _privateProperty = 0; public int publicProperty { get { return _privateProperty; } set { _privateProperty = value; } } }

In this example, publicField will be visible and editable to the Unity editor. Even _privateProperty will be visible to the editor (just not editable). However, publicProperty will not be accessible at all.

Is there any way to make properties exposed to the editor?

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

7 Replies

· Add your reply
  • Sort: 
avatar image
19
Best Answer

Answer by Ricardo · Apr 13, 2010 at 07:02 AM

You may want to write a custom editor. Unity just can't safely blanket serialize/deserialize properties, since getters and setters can have side effects.

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image capnbishop · Apr 14, 2010 at 01:20 AM 1
Share

That makes sense. Now I feel silly for not thinking of that. Thank you.

avatar image Ricardo · Apr 14, 2010 at 06:49 AM 1
Share

Heh, don't sweat it. Notice that I said blanket. They could, for instance, have attributes to indicate that a property getter can be safely called, or that a private member should be called ins$$anonymous$$d of a setter. Do vote for the request that Jessy linked to if you're interested on that sort of thing.

avatar image
23

Answer by DenninDalke · Apr 27, 2012 at 01:51 AM

This work fine for me:

[SerializeField]
private int _SomeProperty;

public int SomeProperty {
get { return _SomeProperty; }
set { DoSomething(); }
}

Your setter will not get called when modified from the inspector, but I think it's not a big problem.

Comment
Add comment · Show 11 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image swquinn · May 17, 2012 at 10:45 PM 0
Share

I've taken to using this solution in my code as well. I think its probably the nicest, simplest, solution if you don't like publicly exposing fields and prefer using properties to manage mutators.

avatar image SarperS · Oct 13, 2012 at 10:52 PM 0
Share

If you are doing data binding via properties, that is a problem. I want my GameObject's name to change when I edit a property in the script but as my custom inspector can't work with properties, I have to check for any changes in the OnInspectorGUI and change the gameobject's name there, messy.

avatar image gilley033 · Apr 23, 2013 at 06:14 PM 0
Share

$$anonymous$$y setter is called a bunch when I modify the value in the inspector. What did you mean by, "Your setter will not get called when modified from the inspector"?

Actually, my setter is called when I just click on the inspector, and when I actually change a value through a property, it is called like 8 times.

avatar image CodeFighter · Jan 07, 2017 at 12:15 PM 0
Share

Thank you! Really helps!

avatar image saporter · Jun 14, 2017 at 02:39 PM 0
Share

Brushing off the cobwebs here and this answer was so helpful. Should be updated as best answer.

Show more comments
avatar image
10

Answer by vexe · Sep 05, 2014 at 05:57 PM

Exposing properties was one of the very first things implemented in VFW, get it, it's free.

I also wrote in-depth answer here explaining how to go about serializing things including auto-properties.

ShowEmAll currently supports serializing interfaces, generics, auto-properties, dictionaries, abstracts, etc.

To expose a property, just annotate with ShowProperty:

alt text


showproperty.png (34.4 kB)
Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image codestage · Sep 18, 2015 at 06:57 PM 0
Share

Great work on your framework, thanks for sharing!

avatar image
7

Answer by Jessy · Apr 13, 2010 at 04:58 AM

No. But you can vote for it.

In addition, you can hide _privateProperty with [HideInInspector] (link) if you want. Also, convention dictates that your properties should begin with a capital letter, if you care.

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image sosh · Jun 16, 2016 at 02:56 PM 2
Share

Link seems broken

avatar image Bunny83 · Jan 07, 2017 at 01:14 PM 0
Share

This feature request was already declined by Unity. The main reason i guess is that serialization / deserialization is mainly done from a seperate thread. Calling user properties would by tricky as it's not possible to proper synchronise the call. Also that would prevent the properties to use most of the Unity API which makes them even less useful.

You can use properties at runtime just fine. If you want validating code inside the editor, write an editor script / custom inspector / propertydrawer for your class / field.

avatar image
7

Answer by sarahnorthway · Jun 01, 2018 at 02:40 AM

It can be done with a PropertyAttribute. An older version of Unity PostProcessing contained GetSetAttribute which calls a field's GetSet if it is changed via the inspector.

Put GetSetAttribute.cs in Assets/Scripts (not Editor):

 using UnityEngine;

 public sealed class GetSetAttribute : PropertyAttribute {
     public readonly string name;
     public bool dirty;
 
     public GetSetAttribute(string name) {
         this.name = name;
     }
 }

Put GetSetDrawer.cs in Assets/Scripts/Editor:

 using System.Reflection;
 using UnityEditor;
 using UnityEngine;
 
 [CustomPropertyDrawer(typeof(GetSetAttribute))]
 sealed class GetSetDrawer : PropertyDrawer {
     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
         GetSetAttribute attribute = (GetSetAttribute)base.attribute;
 
         EditorGUI.BeginChangeCheck();
         EditorGUI.PropertyField(position, property, label);
 
         if (EditorGUI.EndChangeCheck()) {
             attribute.dirty = true;
         } else if (attribute.dirty) {
             var parent = GetParentObject(property.propertyPath, property.serializedObject.targetObject);
 
             var type = parent.GetType();
             var info = type.GetProperty(attribute.name);
 
             if (info == null)
                 Debug.LogError("Invalid property name \"" + attribute.name + "\"");
             else
                 info.SetValue(parent, fieldInfo.GetValue(parent), null);
 
             attribute.dirty = false;
         }
     }
 
     public static object GetParentObject(string path, object obj) {
         var fields = path.Split('.');
 
         if (fields.Length == 1)
             return obj;
 
         FieldInfo info = obj.GetType().GetField(fields[0], BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
         obj = info.GetValue(obj);
 
         return GetParentObject(string.Join(".", fields, 1, fields.Length - 1), obj);
     }
 }

Use it like this:

 using UnityEngine;
 using UnityEngine.UI;
 
 public class MyComponent : MonoBehaviour {
 
     [SerializeField, GetSet("fillAmount")]
     private float _fillAmount = 0.5f;
     public float fillAmount {
         get {
             return _fillAmount;
         }
         set {
             Debug.Log("Calling set!");
             _fillAmount = value;
             fillImage.fillAmount = value;
         }
     }
 }

Comment
Add comment · Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Dioinecail · Aug 03, 2018 at 09:55 AM 1
Share

Thank you! It's a great solution, just what i was looking for tesing my float scriptable variables which had custom setters

avatar image joeldavidklassen · Aug 13, 2018 at 02:23 PM 1
Share

[Edit: This code wont work. For a list, the path includes Array.data[x]. Now "data[x]" is the field I am trying to access by parsing out the "x" and getting the xth element of the Array. But the na$$anonymous$$g of the data elements of the array don't necessarily correspond to their order in the array, as I've just discovered, so this wont work. Does anyone have any idea how to use the path to deter$$anonymous$$e what element of the array I should access? ]

I wanted to have lists of objects with exposed getters and setters, but the GetParentObject subroutine was failing on those cases, so I hacked together an addition which seems to solve that problem. I am putting it here with no guarantee on its correctness. public static object GetParentObject(string path, object obj) { var fields = path.Split ('.'); var type = obj.GetType ();

     if (fields.Length == 1){
         return obj;
     }
 
     if (isList(obj)) {
         string dataEntry = fields [1];
         var delimiters = new Char[] { '[', ']' };
         var parts = dataEntry.Split (delimiters);
         int index = 0;
         if (Int32.TryParse (parts [1], out index)) {
             FieldInfo[] tempfields = type.GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
             foreach (FieldInfo field in tempfields) {
                 if (field.FieldType.IsArray) {
                     Array array = field.GetValue (obj) as Array;
                     object listEntry = array.GetValue (index);
                     return GetParentObject (string.Join (".", fields, 2, fields.Length - 2), listEntry);
                 }
             }
 
         }
     }
 
     FieldInfo info = obj.GetType().GetField(fields[0], BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
     obj = info.GetValue(obj);
 
     return GetParentObject(string.Join(".", fields, 1, fields.Length - 1), obj);
 }
 
 private static bool isList(object val){
     return (val.GetType ().IsGenericType && val.GetType().GetGenericTypeDefinition () == typeof(List<>));
 }
avatar image jjkljlkfjjkljh joeldavidklassen · Apr 16, 2019 at 07:25 PM 0
Share

I think I got this to work with arrays but I haven't tested it with lists. $$anonymous$$aybe my changes will help you in the right direction though if it doesn't work for lists.

 using System.Reflection;
 using UnityEditor;
 using UnityEngine;
 using System;
 
 [CustomPropertyDrawer(typeof(GetAndSetAttribute))]
 sealed class GetSetDrawer : PropertyDrawer
 {
     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
     {
         GetAndSetAttribute attribute = (GetAndSetAttribute)base.attribute;
 
         EditorGUI.BeginChangeCheck();
         EditorGUI.PropertyField(position, property, label);
 
         if (EditorGUI.EndChangeCheck())
         {
             attribute.dirty = true;
         }
         else if (attribute.dirty)
         {
             object parent = GetParentObject(property.propertyPath, property.serializedObject.targetObject);
 
             Type type = parent.GetType();
             Type arrayType = type.IsArray ? type.GetElementType() : null;
 
             PropertyInfo info = arrayType == null ? type.GetProperty(attribute.name) : arrayType.GetProperty(attribute.name);
 
             if (info == null)
             {
                 Debug.LogError("Invalid property name \"" + attribute.name + "\"");
             }
             else
             {
                 if(arrayType == null)
                 {
                     info.SetValue(parent, fieldInfo.GetValue(parent), null);
                 }
                 else
                 {
                     for (int i = 0; i < ((Array)parent).Length; i++)
                     {
                         object newParent = ((Array)parent).GetValue(i);
                         info.SetValue(newParent, fieldInfo.GetValue(newParent), null);
                     }
                 }
             }
 
             attribute.dirty = false;
         }
     }
 
     public static object GetParentObject(string path, object obj)
     {
         string[] fields = path.Split('.');
 
         if (fields.Length == 1)
             return obj;
 
         FieldInfo info = obj.GetType().GetField(fields[0], BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
         if (info != null) { obj = info.GetValue(obj); }
         
         return GetParentObject(string.Join(".", fields, 1, fields.Length - 1), obj);
     }
 }
avatar image Rxzlion · Aug 23, 2018 at 11:39 PM 0
Share

First of all you didn't write this code! It was taken from here link text so give credit next time to the writer of the code!

Second thing this won't work for lists not even with the fix posted above.

avatar image v-ercart Rxzlion · Aug 24, 2018 at 04:40 PM 0
Share

Didn't she give credit for that code to "An older version of Unity PostProcessing"? That's probably the common link between her code and your link.

  • 1
  • 2
  • ›

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

21 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Can't find serialized field in Animation Window 1 Answer

How to expose a field of type Interface in the inspector? 10 Answers

Material doesn't have a color property '_Color' 4 Answers

expose public property (not variable) in inspector 9 Answers

Doesn't the C# JIT inline property getters in Unity? 3 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges