Json Deserialized example

I’ve been a really good boy… Honest…

1 Like

My present to Justin

2 Likes

Is that a precious mineral from outer space?

I think it is a lump of coal…but could be from a dinosaur.

Here’s mine to you - i know your a closet mod :rofl:

906de9b8692e4504bed3e6877aa19c77

OUCH! Darn whippersnapper

If add

public enum MyEnum : short { A, B, C };

and add field in TestClass

public MyEnum e;

then

var newInstance = (TestClass)JsonConverter.DeserializeObject(stringValue, typeof(TestClass), CreateInstance);

in the DoComplexObjectTest() don`t work → exception

Enums and structs are going to be problematic. There is a bug in TinyCLR where .ToString() on enums and structs causes an exception. I can look at this, but until that bug is fixed, I may not be able to fix this.

The bug : ToString() fails on structs, including Guid · Issue #476 · ghi-electronics/TinyCLR-Libraries · GitHub

So, I poked into this a bit deeper and there are two ways I could fix this - I could either serialize enums as integers (which I think is the common practice, and makes more sense for flag enums) or as a string or array of strings for flags (which isn’t very json-ish, not portable, but would at least round-trip locally).

I am blocked on both paths though. I can’t use the string serialization because .ToString() crashes for enums and structs, as mentioned above (and, well, this is a pretty non-standard way to serialize enums in JSON anyway, so not sure it would make sense even if I could do it).

And I am blocked on using a ulong (integer) serialization because TinyCLR is missing the Convert.ChangeType() function, so I can’t do the necessary type coercion between ulong and the enum type during deserialization (though serialization seems to work).

So, enums are out of reach for now. If I had to make a request, it would be for an implementation of Convert.ChangeType().

With suggestions from @taylorza, I dug into this a bit deeper. I found that I could make this work if I could cast to a scalar that matches the scalar type that underlies the Enum. But, I ran into a crash. Both Enum.GetUnderlyingType(Type enumType) and Enum.ToString() fail for the same reason:

From enum.cs in mscorlib:

    public override string ToString() => this.GetType().GetField("value__").GetValue(this).ToString();
    public static Type GetUnderlyingType(Type enumType) => enumType.GetType().GetField("value__").FieldType;

GetField(“value__”) returns null, so both GetUnderlyingType() and ToString() throw exceptions.

Fixing this would fix ToString, and allow me to make the JSON lib work for enums.
Maybe “value__” was something that the C#2.0 compiler generated, but Roslyn does not.

Thanks for looking into this and going that deep. I am sure Santa has you on the nice just :slightly_smiling_face: not sure what we can do and when but please make an issue.

No worries Gus. This is the fix that needs to go into enum.cs in mscorlib. This accounts for the way that Roslyn stores type information. I suspect a similar fix will fix ToString for structs:

                // This is broken in TinyCLR
                //var baseType = Enum.GetUnderlyingType(targetType);

                // But this is a substitute from the Microsoft mscorlib source...
                var fields = targetType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                if (fields == null || fields.Length != 1)
                    throw new Exception("Failed to get enum underlying type");

                var baseType = fields[0].FieldType;

I’ll submit a pull request once I test it separately from the Json work.

7 Likes

Oh you are even providing the fix!! My man, thanks!

4 Likes

I also now have a fix for the Json and enums issue - two PR’s forthcoming

4 Likes

Json PR is here : Add support for enums by martincalsyn · Pull Request #995 · ghi-electronics/TinyCLR-Libraries · GitHub

1 Like

@mcalsyn, looking at the Enum.GetUnderlyingType() I think the solution might be simpler. It looks like the bug is actually the extra call to GetType() on the enumType.

The following should do the trick

public static Type GetUnderlyingType(Type enumType)
{
    if (enumType == null) throw new ArgumentNullException();
    if (!enumType.IsEnum) throw new ArgumentException();
    return enumType.GetField("value__").FieldType;
}
2 Likes

Will there, can there be a way to implement a protocol like OpenADR 2.0b.?
Such protocol uses XML, with embedded schema definitions…yadi-yada.
Pretty much the full boatload of XML.

Our implementation runs on the full blown .Net Framework on a PC /Server, etc.
.net MicroFramework did not have the XML capabilities required to make such work, without wonky roll-your-own code.

Can, will, tinyCLR be able to incorporate a substantial portion of .Net Framework XML libraries…someday.?

Yes, json and better bson would be preferred, yet we have to access services built upon such XML protocol. No way around such.

Here is a link to the OpenADR 2.0b protocol…if of any interest.
https://www.openadr.org/specification

TinyCLR is not a full framework replacement, but it is better than the full framework, at hardware and IoT tasks. We keep adding to it and Keep on pushing the limits, but we always have to be careful not to bloat a system that is meant to run on small devices.

And as an added bonus, all TinyCLR libraries are open source. Martin generously contributed the json library for example. And we welcome any similar, commercially viable, contributions.

10-4

Understand the bloat and all, and agree keep the focus on the tiny.

Yes, for hardware and IoT tasks…not even a question as to the ability of tinyCLR and associated hardware to bend the traditional development curve.

Being able to build / code edge IoT devices, server middleware, web (Laptop / Mobile), Machine Learning, AI…all within, essentially, the same development environment

…Absolutely Fabulous.!!!

1 Like

I have a fairly complex json string that I can successfully parse under preview 3 but when I move the code to preview 4 I’m getting an unhandled null reference exception. I have narrowed the issue down to creating the instance with a custom array object ( daily[] ) in the root of the object, the name and length properties are null, and -1 no matter what I try. If I use a native type (string[]) it initialized as expected.

I have created a ready to run test project that includes working code for preview firmware 3 and the same example with firmware 4 that fails. Any advice anyone might have to get this code working under preview 4 would be greatly appreciated.

JsonTest.zip

static void Main()
{
    string validJson = "[see test project for full string and custom objects]";
    Debug.WriteLine(validJson);  // This is valid JSON.  Checked on a couple differnt websites.

    var jsonResponse =  (WeatherResponse)JsonConverter.DeserializeObject(validJson, typeof(WeatherResponse), CreateInstance);
    Debug.WriteLine($"Temp: {jsonResponse.current.temp}");

}

private static object CreateInstance(string path, JToken root, Type baseType, string name, int length)
{
    if (path == "/" & name == "daily")
        return new Daily[length];

    else if (path == "//daily" & name == null)
        return new Daily();

    else if (path == "//daily" & name == "weather")
        return new Weather[length];

    else if (path == "//daily/weather" & name == null)
        return new Weather();

    else if (path == "/current" & name == "weather")
        return new Weather[length];

    else if (path == "/current/weather" & name == null)
        return new Weather();

    else
        return null;
}