Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 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
0
Question by benapprill · Oct 13, 2019 at 12:22 AM · unityeditorscriptableobjectreference

Pass ScriptableObject field into a function by reference

I have a ScriptableObject

 public class Data : ScriptableObject
 {
   public string dataToUse;
 }


I can pass Data as a parameter, and it properly works as a reference


 public class UsesData
 {
   Data data;

   public UsesData(Data data)
   {
     this.data = data;
   }
   public void HandleData()
   {
     //This works just fine. It updates the Data instance field by reference
     data.dataToUse = "newData";
   }
 }


However, I would like to pass the field itself as a reference, instead of the ScriptableObject


 public class UsesData
 {
   string dataToUse_Ref;

   public UsesData(string dataToUse)
   {
     this.dataToUse_Ref = dataToUse;
   }
   public void HandleData()
   {
     //This is only passing by value
     dataToUse_Ref = "newData";
   }
 }


Then, a client can pass in the field, instead of the entire object


 public class Client
 {
   //Assume Data is initialized before-hand
   Data data;

   UsesData usesData;

   public Client()
   {
     usesData = new UsesData(data.dataToUse);

     //This should update the Data field by reference, but does not because of passed-by-value
     usesData.HandleData();
   }        
 }


I fiddled around with using the ref keyword, but it did not work


 public class UsesData
 {
   string dataToUse_Ref;

   public UsesData(ref string dataToUse)
   {
     this.dataToUse_Ref = dataToUse;
   }
   public void HandleData()
   {
     dataToUse_Ref = "newData";
   }
 }


 public class Client
 {
   Data data;

   UsesData usesData;

   public Client()
   {
     usesData = new UsesData(ref data.dataToUse);

     usesData.HandleData();
   }        
 }


Not sure if I am missing some syntactical sugar, or if this approach is just not possible for some reason. It seems like the ref keyword "should" work for something like this.

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

2 Replies

· Add your reply
  • Sort: 
avatar image
0

Answer by Bunny83 · Oct 13, 2019 at 01:42 AM

This is not possible. Yes the ref keyword actually passes a true managed "pointer" to the memory location where the field is stored to the method that has a ref parameter. However the ref parameter can only be used inside that method. Such a ref-pointer can not be "stored" for later use. Something like that is only possible with true unsafe code which is not recommended and also isn't supported by many target platforms.


Even strings are reference types (since they are objects and allocated on the heap), strings are immutable objects in C#. So once created they can not be changed. If you need the control flow you showed, your only real option is to pass the wrapping object as parameter and have your method modify the field of that referenced object.


An alternative is to use get and set delegate methods to carry out your change. This essentially uses a wrapping class (a closure object) though it all happens implicitly. Something like that:

 public class UsesData
 {
     System.Func<string> getData;
     System.Action<string> setData;
     public UsesData(System.Func<string> aGetMethod, System.Action<string> aSetMethod)
     {
         getData = aGetMethod;
         setData = aSetMethod;
     }
     public void HandleData()
     {
        setData("newData");
     }
 }

You would use it like this:

 usesData = new UsesData(()=>data.dataToUse, d=>data.dataToUse = d);
 usesData.HandleData();
Comment
Add comment · 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
0

Answer by benapprill · Oct 13, 2019 at 03:26 AM

A shout-out to @Bunny83, who gave a great response on the technicalities of using the ref keyword.


As he stated, the use of the ref keyword I was originally trying to use does NOT work for storing a reference for later use.


I managed to find a solution for my problem by using SerializedProperties and SerializedObjects.


 public class Data : ScriptableObject
 {
     public string fieldToUse;

     SerializedObject objSerialized;
     public SerializedProperty fieldToUseSerialized;

     private void OnEnable()
     {
         objSerialized = new SerializedObject(this);
         fieldToUseSerialized = objSerialized.FindProperty("fieldToUse");
     }
 }

 public class UsesData
 {
     SerializedProperty fieldToUseSerialized;

     public UsesData(SerializedProperty property)
     {
         fieldToUseSerialized = property;
     }

     public void HandleData()
     {
         fieldToUseSerialized.stringValue = EditorGUILayout.TextField(fieldToUseSerialized.stringValue);
         fieldToUseSerialized.serializedObject.ApplyModifiedProperties();
     }
 }

 public class Client
 {
     //ScriptableObject, initialized through inspector somehow
     Data data;

     UsesData usesData;

     public Client()
     {
         usesData = new UsesData(data.fieldToUseSerialized);

         //Changes to the Data field now take affect through the SerializedProperty
         usesData.HandleData();
     }
 }


Basically, instead of passing in the data field directly, I bound it to a SerializedProperty, and affected the change through that. This works fine for a SerializedObject, but a normal class that cannot be serialized like this, will still run into the same issue of not being able to store a reference for later.

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 Bunny83 · Oct 13, 2019 at 11:30 AM 0
Share

This doesn't make much sense on several levels. First of all a SerializedObject instance will hold a reference to the serialized object. A SerializedProperty will hold a reference to it's SerializedObject. Both actually perform the serialization on the native code side through reflection. So this is much more complex than anything I had mentioned.


Though your main issue is that SerializedObject and SerializedProperty are editor classes which can not be used at runtime in a build. Since your Data class contains a field of type SerializedProperty the class can not be used at runtime. So this answer seems really strange. Even if this is a question about pure in editor code (which you have only mentioned in the tags), your Data class can not be used at runtime.


The main question is why do you want to pass in a string field anonymously to that method. If it's just for editor code, then yes, SerializedProperty is the way to go, but it's completely wrongly placed in your ScriptableObject. All in all your question description is way too abstract to deter$$anonymous$$e what your usecase is.

avatar image benapprill Bunny83 · Oct 20, 2019 at 02:07 AM 0
Share

Yes, my goal is more for Editor code. I am trying to separate my Editor Window view code from the rest of it. For that, I am trying to bind the input fields to my data object.

I suppose you are correct, and my answer is too specific for my question. The question was asking how to do the reference at any time, not just outside of runtime in the Editor.

While my solution works, it requires extra serialization code. It winds up being a bit easier to just use the ref keyword as part of a function parameter. And at that point... breaking out the binding to its own class becomes unnecessary.

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

117 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 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 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 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 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 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

Scriptable object keeps referencing the objects? 1 Answer

Do you have to set a object reference for every script? 0 Answers

[CreateAssetMenu] For inherited ScriptableObjects 1 Answer

creating scriptableObject with data from scene in editor 0 Answers

Scriptable Objects, how to force Include in Compile / Build without referencing it in the scene? 1 Answer


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