I created a simple class with one field. class Test{int value;}
If I use the "preserve references" feature and set it to "all" (i.e. both objects and arrays), then when I simply serialize an array of Test objects, it gets serialized as a JSON object with a special "$values" member with the array values, along with the expected "$id" property to preserve the array reference. That much is fine, but once again the whole thing breaks on deserialization.
Stepping through the source code, I discovered that simply because the test for "IsReadOnlyOrFixedSize" is true, it sets a flag "createdFromNonDefaultConstructor" to true, which doesn't even make any sense, because although it is a fixed size array, it is created from a default constructor, unless it considers any fixed size array constructor a non-default constructor. The bottom line is that it should be able to handle something so basic, and yet it throws this error: "Cannot preserve reference to array or readonly list, or list created from a non-default constructor".
How can I deserialize a basic array while preserving all references in JSON.NET without getting an error?
Got the same issue, I used List<T> instead of T[] to fix it.
You are most likely missing a call to ToObject(...) and a type cast.
This should work:
class Test { public int Value; }
class Program
{
static void Main(string[] args)
{
var array = new Test[2];
var instance = new Test {Value = 123};
array[0] = instance;
array[1] = instance;
var settings = new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.All
};
string serialized = JsonConvert.SerializeObject(array, settings);
// Explicitly call ToObject() and cast to the target type
var deserialized = (Test[]) ((JArray)JsonConvert.DeserializeObject(serialized, settings)).ToObject(typeof(Test[]));
Debug.Assert(deserialized[0].Value == 123);
}
}
Related
I'm trying to be notified when an array changes its content.
Through this code I'm able to notify the setting of the array, but nothing happens when a new item is inserted.
var array: MutableMap<String, List<String>> = mutableMapOf()
set(value) {
field = value
arrayListener?.notify()
}
The only thing I came up with is resetting the array to itself everytime I add, delete o edit items, like this:
array = array
I read this question How to watch for array changes? relative to Javascript, but I'd like an easier solution then creating a new object, can anyone suggest it?
Array's API is quite simple: elements can be written there and can be read from an array.
At 99% (a number without justification, read "the vast majority") array's usages people are satisfied with this simple API. It would be a shame if a simple interface with straightforward implementation was mixed with tricky functionality.
Moving to your problem, a possible approach could be create an array's wrapper
class ArrayWrapper<T> (private val array: Array<out T>,
private val onChange: () -> Unit) {
val size = array.size
fun get(index: Int): T {
return array[index]
}
fun set(index: Int, value: T) {
array[index] = value
onChange()
}
}
An example of usage:
val ints = ArrayWrapper(arrayOf(1, 2, 3)) {
println("Array has been changed")
}
You are currently only observing that a new map is assigned to array variable. Your code won't notify you if the map entry is added or removed from the map.
If you want to observe if the array is reassigned you can use an Observable delegate from Kotlin standard lib.
Note: You should rename array variable that it fits a data structure you have used.
Here is an example:
var map: MutableMap<String, List<String>> by Delegates.observable(mutableMapOf()) {
property, oldValue, newValue ->
if (oldValue != newValue) //notify that reference has changed
}
You can read about observable delegate here.
Since you want to observe changes in the map I think you should take a look at this question. It might help. To archive what you want, you'll have to extend map or create a wrapper around it which will notify you when a map entry is added or removed.
I'm super new to programming so this may be a pretty basic question.
I have an array of NSButtons (checkboxes) in my ViewController that I am calling "buttonArray." I want to go through the array, find out which buttons are checked and add the indexes of those checked buttons to another array of integers (located in a struct), which I am calling "intArray." This is the struct:
struct GetInterval {
var intArray = [Int]()
mutating func putIntIntoArray (intToAdd:Int) {
self.intArray.append(intToAdd)
}
}
I have tried doing this two ways (shown below), both of which have given me compiler errors.
First, I tried to use a function to import the index as an Int and add it to the "intArray" array...
for interval in buttonArray {
if interval.state == NSOnState {
var intervalIndex = find(buttonArray, interval)
GetInterval.putIntIntoArray(Int(intervalIndex!))
}
}
...which gave me the error: "Cannot invoke 'putIntoArray' with argument list of type ((int))"
When that didn't work, I tried appending it directly from the "if" statement in the ViewController...
for interval in buttonArray {
if interval.state == NSOnState {
var intervalIndex = find(buttonArray, interval)
GetInterval.intArray.append(intervalIndex!)
}
}
...which gives me the error: "GetInterval.Type does not have a member named 'intArray'"
How can I fix this?
When you say GetInterval.(something), this refers to a static member (a.k.a., something owned by the GetInterval type). However, your intArray is a member owned by each instance of the GetInterval type. So you need to create an instance first. For example:
var getInt = GetInterval() // create a new instance
getInt.putIntIntoArray(...) // modify this instance, by calling a mutating function
getInt.intArray.append(...) // modify this instance, by directly accessing a property
I have an array myArr where I keep objects named item1, item2, item3... etc.
trace(myArr[myRandomNumber2][myRandomNumber1]); this randomly returns [object Item1], [object Item2] etc.
I need to make If statement somthing like this:
if (myArr[myRandomNumber2][myRandomNumber1] == Item7) {
//do something
}
But this doesn't work. I don't get any errors, just nothing happens. How to check current elements name?
You cannot compare two objects directly using equality operator (either == or ===). The equality operator looks to the reference address if you are using it on objects.
Each time you create a new object, your variable (or the array) holds the reference address to the newly created object.
Ofc the reference address aren't equal, that's why you are getting false result. You can compare objects in two ways, for me, the first one is preferred.
Here below is an example of an class to create objects with ;
public class MyObject {
public var name:String;
public var info:String;
public function MyObject(newName:String, newInfo:String) {
this.name = newName;
this.info = newInfo;
}
}
1. Define a custom compareTo() method,
Add the next method in your class, here in MyObject,
public function CompareTo(otherObject:MyObject):Boolean {
// check properties and compare each properties
return (this.name == otherObject.name && this.info == otherObject.info);
}
This will only return true if the properties are equal. You might use the compare operator with strings. Just expand the above with all properties. If your properties are not public, please use the getters to obtain the property values from other objects. For the current object, this. is enough.
Then in your code,
if (myArr[myRandomNumber2][myRandomNumber1].compareTo(Item7)) {
//do something
}
or
if (Item7.compareTo(myArr[myRandomNumber2][myRandomNumber1])) {
//do something
}
both does the same.
2. use the compare() method from ObjectUtil class
Please refer first to this documentation and the explanation (with example) on it.
Then check the next statement
ObjectUtil.compare(myArr[myRandomNumber2][myRandomNumber1], Item7)
This will compare both objects using the properties in the Item object. Please note that this doesn't work if you have a class as a property. You can add a depth option to the above method to do a deep comparison. Still it might be a bit inaccurate if you have polymorph objects.
The result of the above method is an integer, either -1 or 0 or 1. Please check the documentation to understand what these numbers represents. You needs the 0 because that says that the compared objects are both equal.
Then your code;
if (ObjectUtil.compare(myArr[myRandomNumber2][myRandomNumber1], Item7) == 0) {
//do something
}
That's how you can start to compare objects correctly.
By default, trace of object with undeclared toString() method writes [object ClassName] in output. So if I understand your description correctly, you can use this:
if (myArr[myRandomNumber2][myRandomNumber1] is Item7) {
//do something
}
If Item7 is not a class as it seems, and not a reference to some object stored in your array, and not an instance of such types as int, Number, String etc., then you can declare your custom comparison function to compare this objects, for example:
if(Item7.compare(myArr[myRandomNumber2][myRandomNumber1])) {
// do someting
}
And in the class of Item7:
// ...
public function compare(obj:*):Boolean {
// your logic here
}
In any other case, your code is just incorrect.
public class Ship
{
public static int[] size = {3, 2, 3, 5, 4};
public static String[] shipNames = {"Destroyer", "Cruiser", "Submarine",
"Aircraft Carrier", "Battleship"};
public Ship(String shipNames[], int size[])
{
this.shipNames[] = shipNames[];
this.size[] = size[];
}
}
Okay so basically what I'm trying to do is make it so my constructor repeats two static variables...
In another class, I'm calling this object Ship...
newShip = new Ship(Ship.shipNames[i],Ship.size[i]);
But when it sends I get these error messages:
Error: illegal start of expression
Error: '.class' expected
Error: illegal start of expression
Error: '.class' expected
Working with arrays is quite confusing for a beginner such as myself. :(
There are many things wrong here.
When you write something like String shipNames[], the [] is not part of the variable name. It is part of the variable type. So when you are just using the variable, you are not supposed to write them.
You declared the constructor to accept arrays, but you are trying to pass single values to it. Which do you actually want to happen?
When you refer to this.shipNames, presumably you mean to set some field of the object you're constructing. But you have not defined such a field. You already have a thing named shipNames in the class, but it's static - it's part of the class, not the instances.
You have several problems with your code.
First is that your are passing the constructor a string and an int, not an array of strings or array of ints here:
newShip = new Ship(Ship.shipNames[i],Ship.size[i]);
Secondly, you need to receive a string and an int in the constructor, as follows:
public String shipName;
public int size;
public Ship(String shipName, int size)
{
this.shipName = shipName;
this.size = size;
}
There might be other syntax and semantic errors too, but those seem to be the most obvious ones to me.
I'm wrote this code a long time ago and thought I understood it at that time but now I'm trying to wrap my head around how it works...
// Main.as
package {
public class Main {
public function Main() {
var fruit:Array = [];
UpdateClass.update(fruit);
trace(fruit); // Traces out the string pushed into it? How??? I think the data would've got lost...
}
}
}
// UpdateClass.as
package {
public class UpdateClass {
public static function update(array:Array):void {
array.push("haha, this is not a fruit!");
}
}
}
I just don't understand how the UpdateClass manages to update Main's fruit array? I'm thinking the data would get lost because it is not returning the new array?... When I try this with Strings and Numbers the data does get lost like expected.
I don't know what I was on when I wrote this but I would like to try and understand the logic behind this.
Thank you.
String and Number are "primitive" data types in AS3, while Array and other objects like MovieClip are "complex" or "reference" data types.
When you pass a primitive, its value is copied, so modifying that doesn't affect the original. When you pass a complex object, it's actually a reference to the object's address in memory, so your function is modifying the original object.
I'm assuming something like following when you say that the value was lost with String and Number:
// UpdateClass.as
package {
public class UpdateClass {
public static function update(num:Number):void {
num = 1;
}
}
}
The reason it was lost was because you got a reference to the original object as num. But the function update changed that reference to another Number object which contained the value '1'. This would be true for array too, if you assign another array to the passed reference like:
// UpdateClass.as
package {
public class UpdateClass {
public static function update(array:Array):void {
array = new Array();
array.push("haha, this is not a fruit!");
}
}
}
But, since you are just calling a method on the passed reference (push), 'array' still refers to the original Array and updates it.