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
1
Question by Igor_Vasiak · Oct 04, 2017 at 05:00 PM · scripting problemloadjsonfilegenerics

Why my Serializable class isn't receiving values from a Generic .json loader?

I'm creating generics for saving and loading process. I really save and load a lot. So, I have decided to make generics. The generic for saving works perfectly, if someone wants it, just take it:

Code:

Save

 public static void SaveToJSON<T> (this T data, string path, string fileName)
 {
     if (!typeof(T).IsClass)
         throw new Exception("Only classes can be passed to this method. " + typeof(T).Name + " is not a class.");

    if (!typeof(T).IsSerializable)
        throw new Exception("The " + typeof(T).Name + "class is not Serializable. Please make it Serializable so the class can be accessed");

     string finalPath = path + fileName + ".json";

     string newFile = JsonUtility.ToJson(data);
     File.WriteAllText(finalPath, newFile);
 }

Even though the generics aren't needed for this, they are really useful, and usually I need to break my head down to make the code fit into my codes, and now I don't need to break my head any longer.


The Issue

For some reason the game is not loading properly. It is probably the .json loader, since I'm getting no value back. The .json loader IS converting the .json file correctly, but I don't know why the values aren't being passed to the Serializable class that I want to be loaded. The code is down here, so you can examine it.


Code:

Load

 public static void LoadFromJSON<T> (this T data, string path, string fileName)
 {
     if (!typeof(T).IsClass)
         throw new Exception("Only classes can be passed to this method. " + typeof(T).Name + " is not a class.");

     if (!typeof(T).IsSerializable)
         throw new Exception("The " + typeof(T).Name + "class is not Serializable. Please make it Serializable so the class can be accessed");

     string jsonString = string.Empty;
     string finalPath = path + fileName + ".json";

     jsonString = File.ReadAllText(finalPath);
     data = JsonUtility.FromJson<T>(jsonString);

     //Debug.Log(jsonString);
 }

You can test it, and use it wherever you want, but if you know why it doesn't work let me know, please. I'm open to suggestions on how to make this code even better.

In case this code is working for you, let me know as well, so I'll post another question with another code pieces to know if those are the cause of the issue. They're not relevant here since they're only DictionaryToString() and FromString() converters.


Thanks in advance.


Here is the .json file that I'm trying to load. I think it is needed so you can see clearly what I'm trying to do. Loading this manually, without the Generic works perfectly, but I want the Generic so it can save me some time.

.json File

 {
     "stats": [
         "Health_100",
         "MaxHealth_100",
         "RegenSpeed_10",
         "Stamna_10",
         "MaxStamna_10",
         "Defense_0",
         "DamageMultiplier_1",
         "CriticalStikeChance_0",
         "Speed_5",
         "Level_0",
         "CurrentXP_0",
         "XPToNextLevel_100"
     ]
 }


The Solution

Okay... A solution found... If anyone reading this just came here to copy/paste, please read @Bunny83 answer. Here is the solved code:

File_Extensions.cs

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
2
Best Answer

Answer by Bunny83 · Oct 04, 2017 at 06:32 PM

First of all keep in mind that Unity's JsonUtility has the same limitations as the normal serialization system of Unity. So make sure whatever you want to serialize meets those requirements.

Second your Json file looks strange. It just contains a string array. Are that your "stringified" dictionary key-values-pairs?

Finally lets solve your actual problem. Method parameters are generally passed by value and therefore whatever is passed into the method can only be used inside the method unless it's a ref or out parameter. Of course the first parameter of an extension method can not be a ref parameter. Therefore this line:

 data = JsonUtility.FromJson<T>(jsonString);

should actually create a new instance of the type "T" and also replace the local variable "data" with the new instance, however you never actually pass that value out of your method. Of course one way would be to use an "out" parameter or simply return the new instance. Though this would make the extension method kind of pointless.

The better solution is to use JsonUtility.FromJsonOverwrite. It allows you to deserialize the JSON and overwrite the values of an existing instance.:

 JsonUtility.FromJsonOverwrite(jsonString, data);

Finally All your checks just limit the usage. You can also serialize structs with the JsonUtility. Also it doesn't necessarily need to be marked as serializable as you can also serialize MonoBehaviours with the JsonUtility. Also if you insist throwing your own exception you should throw an appropriate exception. In your case an ArgumentException would be a better fit.

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 MacDx · Oct 04, 2017 at 06:39 PM 0
Share

@$$anonymous$$ultipleGameStyles Bunny is right, using JSonUtility.FromJsonOverwrite is a much better option than having an out parameter. Please use his answer ins$$anonymous$$d.

avatar image Igor_Vasiak · Oct 04, 2017 at 09:32 PM 0
Share

Okay, okay. Thanks, @Bunny83 . Your solution is better. For me, the simple the better. Your solution gives me that. Thanks.

And, answering your question, the .json file is a Dictionary of stats converted into an array of strings.

avatar image
2

Answer by MacDx · Oct 04, 2017 at 06:03 PM

When working with extension methods you cannot switch the reference of the calling object as you are doing right now, what you need to do is modify the object contents instead. However since you are working with generics you can't really know the contents of the object so IMO, your best option is to add an extra out parameter of type T and pass the calling object. Like this:

 public static void LoadFromJSON<T>(this T data, string path, string fileName, out T dataOut)
 {
     if (!typeof(T).IsClass)
         throw new Exception("Only classes can be passed to this method. " + typeof(T).Name + " is not a class.");
     if (!typeof(T).IsSerializable)
         throw new Exception("The " + typeof(T).Name +
                                 "class is not Serializable. Please make it Serializable so the class can be accessed");
     string jsonString = string.Empty;
     string finalPath = path + fileName + ".json";
     jsonString = File.ReadAllText(finalPath);
     dataOut = JsonUtility.FromJson<T>(jsonString);
     Debug.Log(jsonString);
 }

And call it like this:

 data.LoadFromJSON("Assets/Resources/","dataFile",out data);

Hope this helps!

Edit: Just for extra clarification, this line in your current LoadFromJSON method is what's causing the problem

 data = JsonUtility.FromJson<T>(jsonString);

Edit: Bunny's solution is better. Instead of an out parameter use JsonUtility.FromJsonOverwrite instead to modify the object contents.

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 Igor_Vasiak · Oct 04, 2017 at 06:16 PM 0
Share

Thanks, it worked. I didn't knew that the reference couldn't be switched as I was doing. Hopefully this code will help someone else. Thanks again.

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

123 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 avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

LitJson load float 2 Answers

Saving GameObject to file 2 Answers

How can I save data to a text/json file and read it back and then assign the values back to the variables ? 2 Answers

using json file for waypoints for vehicle in unity project. 0 Answers

Executing code from a text file and writing changes to it 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