Currently I have this function that loads an integer from a JSON file, and then it sets the ExeBalance to the Integer it found in the JSON file however when checking the breakpoints I see that the JSON JBalance gets retrieved correctly, but it won't change the ExeBalance integer.
It is setting it to the JSON object, but It won't change the ExeBalance value:
ExeBalance = saveDataJson.JBalance;
This is my code:
namespace Money_Simulator
{
public class DataObject
{
public int JBalance { get; set; }
}
internal class DataHandler
{
public int ExeBalance = 0;
public void AddBalance(int amt)
{
ExeBalance = ExeBalance + 1;
Console.WriteLine(ExeBalance);
}
public void LoadSave()
{
string filePath = Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
"savedata.json"
);
StreamReader sr = new StreamReader(filePath);
string saveDataContent = sr.ReadToEnd();
var saveDataJson = JsonConvert.DeserializeObject<DataObject>(
saveDataContent
);
ExeBalance = saveDataJson.JBalance;
Console.WriteLine("ExeBalance was set to this value from reading savedata.json:");
Console.WriteLine(ExeBalance);
}
}
}
The contents of savedata.json are {"JBalance": 5}.
The problem with your code is that you don't understand how this should work. My guess is you would like to add an amount to the balance that is stored in your JSON. I've modified your code to do just that. The Load() returns the deserialized JSON object. The AddBalance then adds the amount (amt) and the Save then saves it to the JSON file. Here's the modified code:
using Newtonsoft.Json;
namespace Money_Simulator
{
public class DataObject
{
public int JBalance { get; set; }
}
internal class DataHandler
{
private const string FileName = #"..\..\..\savedata.json";
public void AddBalance(int amt)
{
var data = Load();
data.JBalance = data.JBalance + amt;
Save(data);
}
private DataObject Load()
{
string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, FileName);
string saveDataContent = File.ReadAllText(filePath);
var saveDataJson = JsonConvert.DeserializeObject<DataObject>(saveDataContent);
Console.WriteLine($"ExeBalance was set to this value from reading savedata.json: {saveDataJson.JBalance}");
return saveDataJson;
}
private void Save(DataObject data)
{
var output = JsonConvert.SerializeObject(data);
File.WriteAllText(FileName, output);
}
}
}
In your main application do the following:
using Money_Simulator;
var handler = new DataHandler();
handler.AddBalance(1);
handler.AddBalance(1);
handler.AddBalance(1);
handler.AddBalance(1);
handler.AddBalance(1);
handler.AddBalance(1);
handler.AddBalance(1);
Result is:
ExeBalance was set to this value from reading savedata.json: 10
ExeBalance was set to this value from reading savedata.json: 11
ExeBalance was set to this value from reading savedata.json: 12
ExeBalance was set to this value from reading savedata.json: 13
ExeBalance was set to this value from reading savedata.json: 14
ExeBalance was set to this value from reading savedata.json: 15
ExeBalance was set to this value from reading savedata.json: 16
Related
I am trying to read from a JSON file a series of items into an Object array.
Unfortunately it comes back as null.
Very similar to this issue Unity C# JsonUtility is not serializing a list
So in my particular situation I have the class for the item:
[Serializable]
public class StateData
{
public string name;
public string location;
public string gameText;
}
The class of the collection of items:
[Serializable]
public class StateDataCollection
{
public List<StateData> stateDatas = new List<StateData>();
}
And the class where this is invoked:
public class JSONReader : MonoBehaviour
{
private const string Path = #"S:\repos\myProject\Assets\gameText\";
void Start()
{
string json = File.ReadAllText(Path + "StateData.json");
StateDataCollection stateDataCollection = new StateDataCollection();
stateDataCollection = JsonUtility.FromJson<StateDataCollection>(json);
}
}
Finally the json
{
"StateData":[
{
"name": "name",
"location":"location",
"gameText" : "gameText"},
{
"name": "name",
"location":"location",
"gameText" : "gameText"},
{
"name": "name",
"location":"location",
"gameText" : "gameText"
}]
}
The object comes back as null.
The file is reading OK.
Any ideas where this is failing?
TY!
I would start by checking a few things first:
Check if the file actually exists. Just use a small Debug.Log(File.Exists(path)).
Try another path -> something save like: Application.persistentDataPath. On Windows this will give you something like: %userprofile%\AppData\Local\Packages<productname>\LocalState. This ensures you being able to read/write from/to files.
Fill the List with actual data so you can differentiate between a saved list and the default list.
Edit 1:
I just replicated your Code and made some adjustments to it. It's not perfect but it definately worked for me.
StateData:
using System;
[Serializable]
public struct StateData
{
public string m_Name;
public string m_Location;
public string m_GameText;
public StateData(string name, string location, string gameText)
{
m_Name = name;
m_Location = location;
m_GameText = gameText;
}
}
StateDataCollection:
using System;
using System.Collections.Generic;
[Serializable]
public class StateDataCollection
{
public List<StateData> m_StateData;
public StateDataCollection() => m_StateData = new List<StateData>();
}
JSONReader:
using System.IO;
using UnityEngine;
public class JSONReader : MonoBehaviour
{
private const string FILENAME = "StateData.json";
private string m_path;
public string FilePath {
get => m_path;
set => m_path = value;
}
void Start()
{
FilePath = Path.Combine(Application.persistentDataPath, FILENAME);
Debug.Log(FilePath);// delete me
StateDataCollection stateDataCollection = new StateDataCollection();
stateDataCollection.m_StateData.Add(new StateData("Peter", "X", "123"));
stateDataCollection.m_StateData.Add(new StateData("Annie", "Y", "42"));
stateDataCollection.m_StateData.Add(new StateData("TheGuyFromTheSupermarket", "Supermarket", "666"));
SaveStateDataCollectionToPath(FilePath, stateDataCollection);
LoadStateDataCollectionFromPath(FilePath);
}
private void SaveStateDataCollectionToPath(string path, StateDataCollection stateDataCollection)
{
// ToDo: some checks on path and stateDataCollection
string json = JsonUtility.ToJson(stateDataCollection, true);// prettyPrint active
File.WriteAllText(path, json);
}
private void LoadStateDataCollectionFromPath(string path)
{
if(File.Exists(path)) {
Debug.Log($"File exists at: {path}");// delete me
string json = File.ReadAllText(path);
StateDataCollection stateDataCollection = JsonUtility.FromJson<StateDataCollection>(json);
// delete me
Debug.Log($"StateDataCollection count: { stateDataCollection.m_StateData.Count}");
int i = 1;
stateDataCollection.m_StateData.ForEach(o => {
Debug.Log(
$"Item Nr.: {i}\n" +
$"Name: {o.m_Name}\n" +
$"Location: {o.m_Location}\n" +
$"GameText: {o.m_GameText}\n\n");
++i;
});
}
}
}
I also added a few Debug.Log()s for testing.
Usage:
Run it once with SaveStateDataCollectionToPath(FilePath, stateDataCollection); active and once without it. The Console should display 3 items.
Edit 2:
I think your issue might have been naming-convention violation. File requires using System.IO;, which beside File also contains Path. Unfortunately you also named your const string "Path".
Questions.
1. How to add, delete, update, read only one entry in a JSON file?
2. Is it possible to programmatically add, delete an entry from the file "SettingJson.json"?
Description.
I suggest using a JSON file to store application settings.
How to read and write the whole file, I figured it out.
If I understand correctly, then:
Delete:
1. Remove the property from the "Settings.cs" class;
2. Delete the property from the file "SettingJson.json";
Add:
1. Add a property from the "Settings.cs" class;
2. Add a property from the file "SettingJson.json";
Update:
???
Read:
???
Settings.cs
namespace ConsoleApp
{
public class Settings
{
public string NameSetting1 { get; set; }
public string NameSetting2 { get; set; }
public string NameSetting3 { get; set; }
}
}
Program.cs
//
using Newtonsoft.Json;
using System.IO;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
Settings[] settings = new Settings[] { };
settings = FillArrayAll();
SaveDataArray(settings);
}
static Settings[] FillArrayAll()
{
Settings[] settings = new Settings[]
{
new Settings()
{
NameSetting1 = "ValueSetting_1",
NameSetting2 = "ValueSetting_2",
NameSetting3 = "ValueSetting_3"
}
};
return settings;
}
static Settings[] FillArrayOneItem()
{
Settings[] settings = new Settings[]
{
new Settings()
{
NameSetting2 = "ValueSetting_2",
}
};
return settings;
}
static void SaveDataArray(Settings[] settings)
{
string path = $"{Environment.CurrentDirectory}\\SettingsFolder\\SettingJson.json";
using (StreamWriter writer = File.CreateText(path))
{
string output = JsonConvert.SerializeObject(settings);
writer.Write(output);
}
}
public Settings[] ReadData()
{
string path = $"{Environment.CurrentDirectory}\\SettingsFolder\\SettingJson.json";
using (var reader = File.OpenText(path))
{
var fileText = reader.ReadToEnd();
return JsonConvert.DeserializeObject<Settings[]> (fileText);
}
}
}
}
Update-1
Based on materials from the answer Pavel Anikhouski - 2020-02-28 16: 16
How to make separate methods?
The "Write" method.
Gets:
key-value (one key or a collection of keys);
path to the file SettingJson.json.
Performs:
- writes data to SettingJson.json.
The Read Method.
Gets:
- key (one key or collection of keys);
- path to the file SettingJson.json.
Performs:
- reads data from SettingJson.json.
Returns:
- key value (values or a collection of values).
You can use Json.Linq for manipulation with json, e.g. create JObject from Settings using FromObject method and manipulate with it
var settings = FillArrayAll();
//create JObject from settings
var created = JObject.FromObject(new { settings });
//convert to json
var json = created.ToString();
//write json to a file
//…
//read it back
var updated = JObject.Parse(json);
//get value by key
var key = updated["settings"]?.FirstOrDefault()?["NameSetting1"];
//add new empty Settings to an array
(updated["settings"] as JArray)?.Add(JObject.FromObject(new Settings()));
//convert the updated object back to json
var resultJson = updated.ToString();
The comments near code should be pretty explanatory.
You can also find some details at Querying JSON with LINQ, Parsing JSON and Creating JSON
Hello I have problem with deserialize xml
First I have class like that
public class ReportsViewModel
{
private DateTime fromDateTime;
[XmlIgnore]
public DateTime FromDateTime
{
get { return fromDateTime; }
set
{
fromDateTime = value;
}
}
[XmlElement]
public int FromDateTimeCal
{
get
{
return fromDateTime.Subtract(DateTime.Today).Days;
}
set
{
var a = fromDateTime.Subtract(DateTime.Today).Days;
a = value;
}
}
private DateTime toDateTime;
[XmlIgnore]
public DateTime ToDateTime
{
get { return toDateTime; }
set
{
toDateTime = value;
}
}
[XmlElement]
public int ToDateTimeCal
{
get
{
return ToDateTime.Subtract(DateTime.Today).Days;
}
set
{
var a = ToDateTime.Subtract(DateTime.Today).Days;
a = value;
}
}
}
And then I serialize them
ReportsViewModel reportVM = new ReportsViewModel();
reportVM.FromDateTime = new DateTime(2019, 02, 18);
reportVM.ToDateTime = new DateTime(2019, 02, 22);
using (StreamWriter sw = new StreamWriter(#"D:\Temp\Report.xml"))
{
XmlSerializer xml = new XmlSerializer(typeof(ReportsViewModel));
xml.Serialize(sw, reportVM);
}
Now I get XML file that contain only FromDateTimeCal and ToDateTimeCal
but the problem begin when I deserialize them.
I using deserialize with ReportViewModel class
using (StreamReader sw = new StreamReader(#"D:\Temp\Report.xml"))
{
XmlSerializer xml = new XmlSerializer(typeof(ReportsViewModel));
ReportsViewModel reportVM = (ReportsViewModel)xml.Deserialize(sw);
reportVM.Dump();
reportVM.FromDateTimeCal.Dump();
reportVM.ToDateTimeCal.Dump();
}
It didn't work. I guess the problem is FromDateTime and ToDateTime property wasn't set.
Can I serialize and deserialize with the same class?
your FromDateTime and ToDateTime are never being assigned a value when you Deserialize..
your set inside your cal properties are not doing anything with the value passed to them.
var a = fromDateTime.Subtract(DateTime.Today).Days;
a = value;
that line is keeping the value and calculated value inside that block but never forwards the calculated value.
im going to just guess and say what you want is something like:
var a = value.Subtract(DateTime.Today).Days;
ToDateTime = a;
but then you are going to run into an issue. when you get the value of ToDateTimeCal and FromDateTimeCal, you are going to run the same calculation again, on a already calculated value. Since you are using the current date in the calculation, and you never save that date in the file - you dont have a way to reverse the value to figure out what the FromDateTime was. Unless you read the date from the file itself. It would make more sense to serialze the FromDateTime instead. But if the original date used in the calculation is not necessary, maybe you can do something like:
[XmlIgnore]
public DateTime FromDateTime
{
get { return fromDateTime; }
set
{
fromDateTime = value;
}
}
[XmlElement]
public int FromDateTimeCal
{
get
{
return fromDateTime.Subtract(DateTime.Today).Days;
}
set
{
fromDateTime = DateTime.Today.AddDays(value);
}
}
i am working with a .net application where i have a web service that returns values in array form and now this array values i want to pass to a class and also as a reference to a private object. But since i am fresh new in programming i do not know how where an with what logic to start.
This is the private obj i created and i want to pass those references where CT is the array type and clsIn is the info that comes from another class but i have no idea how to pass neither of them.
private object TotInfo(clsIn In, CT ct)
{
TotInfo objFromCD = new TotInfo();
return objFromCD;
}
And here is the new class i have created that where i want to pass all the values from clsIn and CT:
public class TotInfo
{
// Object properties
private string LAST_OFFER;
private string LAST_OFFER_DATE;
private string CLOSING_REASON;
private string _NO;
private string _STATUS;
#region "GET/SET Property"
public string NO
{
get { return _NO; }
set { _NO = value; }
}
public string LAST_OFFER
{
get { return _LAST_OFFER; }
set { _LAST_OFFER = value; }
}
public string LAST_OFFER_DATE
{
get { return _LAST_OFFER_DATE; }
set { _LAST_OFFER_DATE = value; }
}
public string CLOSING_REASON
{
get { return _CLOSING_REASON; }
set { _CLOSING_REASON = value; }
}
public string STATUS
{
get { return _STATUS; }
set { _STATUS = value; }
}
#endregion
#region "Costruttori"
public CardsTotInfo() { }
public CardsTotInfo(string No, string lastOffer, string lastOfferDate, string closingReason, string status)
{
this.NO = No;
this.LAST_OFFER = lastOffer.ToUpper();
this.LAST_OFFER_DATE = lastOfferDate.ToUpper();
this.CLOSING_REASON = closingReason.ToUpper();
this.STATUS = status.ToUpper();
}
}
I have passed, or better say i think i have passed in the correct way the values of clsIn but i do not know how to pass the properties of the array type CT[].
I really need help.
Thank you in advance.
If CT is an object array and the data you get from the web service always comes in the same order, for instance using an arbitrary example:
object[] CT = { 1, DateTime.Now, "foo", true }
If you know that each property data inside the array will always be at the same index (you will always have a int in index 0 representing an Id, and a DateTime on index 1 representing the last offer day and so on)
I would say you need to set each property "manually":
private object TotInfo(clsIn In, CT ct)
{
TotInfo objFromCD = new TotInfo();
//get data from DB
//set the data from the array into the class properties
objFromCD.Id = (int)ct[0];
objFromCD.LastOfferDate = (DateTime)ct[1];
objFromCD.ClosingReason = (string)ct[2];
objFromCD.Available = (bool)ct[3];
return objFromCD;
}
I tried to return the List from a method. But I got only the last iterate data in the list. Where do I made a mistake? It overwrites the data at every loop in the list.
public class ProjectData
{
public string name { get; set; }
public string id { get; set; }
public string web_url { get; set; }
}
public static List<ProjectData> GetProjectList()
{
int pageCount = 0;
bool check = true;
List<ProjectData> copy = new List<ProjectData>();
List<ProjectData> projectData = new List<ProjectData>();
while (check)
{
ProjectData NewProjectData = new ProjectData();
pageCount = pageCount + 1;
string userURL = "http://gitlab.company.com/api/v3/groups/450/projects?private_token=token&per_page=100&page=" + pageCount;
HttpWebRequest requestforuser = (HttpWebRequest)WebRequest.Create(userURL);
HttpWebResponse responseforuser = requestforuser.GetResponse() as HttpWebResponse;
using (Stream responseStream = responseforuser.GetResponseStream())
{
StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);
var JSONString = reader.ReadToEnd();
projectData = JsonConvert.DeserializeObject<List<ProjectData>>(JSONString);
if (JSONString == "[]")
{
check = false;
break;
}
}
copy = projectData.ToList();
}
return copy;
}
I know there are more that 300 data available to fill in the list. I checked it by using break point. In that, I found all the data are fetching correctly.But it was not copied to the copy<>list. Each and every time It is being overwritten in the copy<> list. How do I prevent the over writing?
In each iteration you are overwriting the values of copy with the current value in the projectData and the last value only will get returned. actually projectData and copy are of the same type ie, List<ProjectData> so you need not convert them again as a List by using .ToList(). In short, you have to use like this :
copy.AddRange(projectData);
Instead for this copy = projectData.ToList();
Replace copy = projectData.ToList();
with copy.Add(projectData.ToList());