How can I deserialize integer number to int, not to long? - c#

I'm using Json.NET to deserialize requests on the server-side.
There is something like
public object[] Values
I need to put in values like 30.0, 27, 54.002, and they need to be double's and int's.
Json.NET has a deserialization property called FloatParseHandling, but there is no option like IntParseHandling. So the question is how can I deserialize integers to int?

Your best bet is to deserialize into a typed model where the model expresses that Values is an int / int[] / etc. In the case of something that has to be object / object[] (presumably because the type is not well-known in advance, or it is an array of heterogeneous items), then it is not unreasonable for JSON.NET to default to long, since that will cause the least confusion when there are a mixture of big and small values in the array. Besides which, it has no way of knowing what the value was on the way in (3L (a long), when serialized in JSON, looks identical to 3 (an int)). You could simply post-process Values and look for any that are long and in the int range:
for(int i = 0 ; i < Values.Length ; i++)
{
if(Values[i] is long)
{
long l = (long)Values[i];
if(l >= int.MinValue && l <= int.MaxValue) Values[i] = (int)l;
}
}

Related

How do I use if/else in a generic function? C#

First I'd like to say that im pretty new in regards to coding, so don't kill me if the code looks horrible.
Alright, so the problem is that im trying to make a generic function which purpose is to take two sorted arrays and merge them into a new sorted array.
The problem im facing is trying to use if's in the function, and it doesn't let me use the < operand.
public object[] mergeTwoSorted<Tone, Ttwo>(Tone[] array, Ttwo[] array2)
{
object[] mergedArray = new object[array.Length + array2.Length];
for (int i = 0; i < mergedArray.Length; i++)
{
if (array is ValueType && array2 is ValueType)
{
if (array[i] > array2[i])
}
}
}
Any idea on how to tackle this problem?
First I'd like to say that im pretty new in regards to coding, so don't kill me if the code looks horrible.
It looks pretty reasonable so far. It looks like what you're trying to do is to take two sorted arrays of two different types, but there is an ordering relationship between the two types. You're then merging the two arrays into an array of objects, such that the objects from the two arrays are still in the same order, but they are interleaved with each other to match the inter-type ordering relation, yes?
That is an unusual thing to do, but it is possible.
If that is not what you are doing, then you need to stop and re-design the code. In particular, if your intention is to take two arrays of the same type, then you must have one type parameter, not two, and you must make an array of T as the output, not object.
The problem is that there is in general no way to express "I have an ordering relationship between these two types" in C#. You'll have to provide a function that does that. Traditionally we provide a function that takes the two types and returns an integer: -1 if the first is the smaller, 1 if the second is the smaller, and 0 if they are equal.
If we have that then your method becomes:
public static object[] MergeTwoSorted<TOne, TTwo> (
TOne[] items1,
TTwo[] items2,
Func<TOne, TTwo, int> comparer)
{
Note that we are using standard C# conventions here. Methods begin with a capital, type parameters are TSomething, and so on. A Func<A, B, C> is a function that takes an A, a B, and returns a C. Methods that do not manipulate an instance of their class are static.
Note that there is no need to re-state in the name of a thing what its type is. Say what the thing is logically, not how it is stored:
object[] merged = new object[items1.Length + items2.Length];
Now your loop needs some work:
for (int i = 0; i < mergedArray.Length; i++)
{
if (array is ValueType && array2 is ValueType)
{
if (array[i] > array2[i])
Arrays are never value types. I think you do not understand the difference between values and references, and that is really important to understand, so do some research on that.
Also, you have a counter i which counts the big merged array, but you use that as an index into the small arrays. That is very wrong; do you see why?
Think about it this way: you are going to count through both arrays at the same time filling in the merged array. So that would be:
int current1 = 0;
int current2 = 0;
while (current1 + current2 < merged.Length)
{
if (comparer(items1[current1], items2[current2]) < 0)
{
// items1[current1] is the smaller
merged[current1+current2] = items1[current1];
current1 += 1;
}
else
{
There is a bug in the code above; can you find it? Hint: indices for all array accesses must be >= 0 and < Length of the array. Is there a way in the code I've written so far that this gets violated?
Can you fix the bug and finish it off?
Can you now make a call site that takes an array of strings, an array of numbers, and an ordering relationship between strings and numbers, and merges the arrays?
public static object[] mergeTwoSorted<Tone, Ttwo>(Tone[] array, Ttwo[] array2)
where Tone : IComparable<Ttwo>
{
var mergedArray = new object[array.Length + array2.Length];
for (int i = 0; i < mergedArray.Length; i++)
{
if (array is ValueType && array2 is ValueType)
{
if (array[i].CompareTo( array2[i] )>0)
}
}
return mergedArray;
}
If you want to use specific operations on Generics, you have to limit them with a where clause accordingly. As when working with Fractural Numebrs, you need a common denominator.
Something like a "IMergable" interface that you have to write yourself.
public IMergeable[] mergeTwoSorted<Tone, Ttwo> (Tone[] array, Ttwo[] array2)
where Tone : IMergeable, Ttwo : IMergeable
{
IMergeable[] mergedArray = new IMergeable[array.Length + array2.Length];
for (int i = 0; i < mergedArray.Length; i++)
{
if (array is ValueType && array2 is ValueType)
{
if (array[i] > array2[i])
}
}
}
Alternatively, you could jsut use one type:
public Tone[] mergeTwoSorted<Tone> (Tone[] array, Tone[] array2)
{
IMergeable[] mergedArray = new IMergeable[array.Length + array2.Length];
for (int i = 0; i < mergedArray.Length; i++)
{
if (array is ValueType && array2 is ValueType)
{
if (array[i] > array2[i])
}
}
}

Read integer or doubles from JsonArray in C#

I have to receive a json file from my server and I need to parse it. Until now, I receive all fields as strings:
{"key1":"12", "key2":"23.5",...}
I read it like this:
JsonArray root = JsonValue.Parse(jsonString).GetArray();
for (uint i = 0; i < root.Count; i++)
{
int id = Convert.ToInt32(root.GetObjectAt(i).GetNamedString("id"));
int state = Convert.ToInt32(root.GetObjectAt(i).GetNamedString("state"));
.....
But now, I receive some of the data as integers or doubles and I don't know how to parse it in the way I did until now because there is no method to return an int with a string given.
{"key1":12, "key2":23.5,...}
System.Json does not allow you to see the difference between integers and floating point numbers. You might want to try Json.NET, which does:
var parsed = JObject.Parse("{\"key1\":12, \"key2\":23.5 }");
foreach (JProperty node in parsed.Children())
{
Console.WriteLine("{0}: {1}", node.Name, node.Value.Type);
}
The output:
key1: Integer
key2: Float
Of course, there are other libraries out there that can deal with JSON, but at least Json.NET works with Silverlight and supports your scenario.

Confusion using SimpleJSON - JSON interpretor

I'm using SimpleJSON which can be found here. <-- Source and documentation.
Here's the JSON that's being output in my PHP script using the json_encode function.
{
"response":3,
"establishments":[
["1","-107.102180","39.410870","0"],
["8","-106.977715","39.377403","7.03707478751404"],
["9","-106.843636","39.484631","14.706647410396497"],
["12","-106.950661","39.230804","14.846070600598637"]
]
}
In the examples on the SimpleJSON page, "establishments" should technically be a nested object, and not a nested array. After going through the code I had assumed that the following would suffice
int id = N["establishments"][0].Value
double long = N["establishments"][1].Value
double lat = N["establishments"][2].Value
Where N is the node containing the Json Information (more info in docs).
However all of these values are returning blank, could anyone point out why? So far arrays have been my only problem with this, and I don't understand the logic behind this enough to figure out what's wrong on my own.
NOTE: As pointed out by #jskidie this is a two dimensional array, I'm having problems returning the full Array (in the 2nd dimension) not the values.
Because you have multi dimensional array. Try:
int id = N["establishments"][0][0].Value
double long = N["establishments"][0][1].Value
double lat = N["establishments"][0][2].Value
What I was looking for was stored in the JSONArray class.
JSONArray array = json["establishments"].AsArray;
for(int i = 0; i < array.Count; i++) {
}
which allows me to iterate over all occurrences.

How to cast/convert values from JSON?

My background is all in dynamic languages for many years, so reasoning about how static typed languages get data from JSON where the key/values can be different types is becoming an issue that really has me stuck. Here's an example of the data I have:
{
"par": 4,
"level": [0,1,0,1,1, 0,1,0,1,1, 0,1,0,1,1, 0,1,0,1,1, 0,1,0,1,1]
}
And I want to get this into some local variables like these
int par;
List<bool> levelData;
I'm using MiniJSON.cs to do the parsing, and it gives me back Dictionary<string, object> but I can't figure out how to get the par and level values from that and convert them to the different types they actually represent.
The problem with trying to convert to List<int> was that MiniJSON parses integers into Int64 and int is 32-bit, so the conversion won't be allowed implicitly because of data loss. Converting to a list of Int64 worked!
List<Int64> cells = (List<Int64>)data["level"];
You have to provide a "decoder" that transforms the dictionary into a typed data structure. This is especially obvious since you are using 0 and 1 to represent boolean values.
Suppose the class SomeClass holds your typed data. The decoder would have to do something like this:
SomeClass decode(Dictionary<string,object> d) {
var m = new SomeClass();
m.par = (int)d["par"];
m.levelData = ((List)d["level"]).Select(x => (int)x == 0 ? false : true).ToList();
return m;
}
So, basically you must turn the (untyped) objects into typed values, and you have to do that explicitly. Note that here it is assumed that your list of zeroes and ones is homogeneous (i.e. does not contain "strange" values like strings, which would be perfectly legal in a dynamically typed language).

Is there a way to make ServiceStack.Redis use JSON.NET instead of ServiceStack.Text?

Is there a way to make ServiceStack.Redis use JSON.NET instead of ServiceStack.Text?
The reason I am asking is because of a specific case where integers are converted to strings in ServiceStack.Text but not in JSON.NET
This is a huge deal when sending data over the wire to the web.
In our specific case, JSON.NET stores data as
'Offset': 0
and ServiceStack.Text stores data as
'Offset' : '0'
Why is this very bad? In javascript, 29 + 0 = 29 but 29 + '0' = '290'. This means array[29 + offset] can yield strange results with ServiceStack.Text
I know this is a specific use case, but it'll be a lot easier to use JSON.NET (which behaves as expected) instead of ServiceStack.Text (which is 3 times faster but does not behave as expected).
It does not store numbers as text, Actual behavior in ServiceStack.Text:
public class HasOffset
{
public int Offset { get; set; }
}
var dto = new HasOffset { Offset = 1 };
string json = dto.ToJson();
json.Print(); //prints {"Offset":1}
var fromJson = json.FromJson<HasOffset>();
Assert.That(fromJson.Offset, Is.EqualTo(1));
If you're trying to deserialize it using JsonObject it gets parsed into a Dictionary<string,string> Dictionary it gets coerced to a string. Likewise if you're trying to store it into a object the serializer doesn't know what type it should convert it to so it leaves it as a string.
At the moment you can only switch between ServiceStack's JsonSerializer and the built-in JsonDataContractSerializer which you can do by adding this to the AppHost.Configure section:
SetConfig(new EndpointHostConfig {
UseBclJsonSerializers = true
});
Please see this thread for the reference to the above information.
It would appear that they simply don't support an out-of-box configurable option for different serializers.

Categories