2

How do I use the (generated) JsonProperty Name = name from JSON file to access a single element in a corresponding C# Class? Here is what I am trying to do …

I have a Xamarin “classic” Newtonsoft application where I load a JSON file into a C# class MagicTime.

Here is the first part of my class - This was generated automatically by the newtonsoft web site using my JSON file

public partial class MagicTime
{
    [JsonProperty("Accel Delay")]
    public long AccelDelay { get; set; }

    [JsonProperty("Accel Period")]
    public long AccelPeriod { get; set; }

    [JsonProperty("Alt DT Step")]
    public long AltDtStep { get; set; }

    [JsonProperty("Beep On Command")]
    public bool BeepOnCommand { get; set; }

    [JsonProperty("Bunt Step")]
    public long BuntStep { get; set; }

    [JsonProperty("Bunt Timeout")]

This is how load/deserialize an instant where loadp is string variable containing the contents of the JSON file

MagicTime MT = JsonConvert.DeserializeObject<MagicTime>(loadp );

This works fine In the application I modify the values of some data element e.g Looking at the above – MT.AccelDelay = 21;

I then reverse the process and write /Serialize I out

That work too.

Now I have an new requirement to use the JsonProperty name to access the corresponding C# data item

It the example above I want to use [JsonProperty("Accel Delay")] to access the corresponding c# element MT.AccelDelay.

I have seen examples where a JSON string is loaded into JObject to do this but not my case where is no (that I can see) JObject

dbc
  • 104,963
  • 20
  • 228
  • 340
RogerM
  • 23
  • 2

1 Answers1

1

You can use Newtonsoft's ContractResolver for this purpose, as it defines how Json.NET maps from c# objects to JSON objects.

First, define the following extension method:

public static partial class JsonExtensions
{
    static readonly IContractResolver defaultResolver = new JsonSerializer().ContractResolver;

    public static T GetJsonPropertyValue<T>(object obj, string propertyName, IContractResolver resolver = null)
    {
        resolver = resolver ?? defaultResolver;
        var contract = resolver.ResolveContract(obj.GetType());
        if (contract is JsonObjectContract objectContract)
        {
            var property = objectContract.Properties.GetClosestMatchProperty(propertyName);
            if (property == null)
                throw new JsonException(string.Format("Unknown property {0}", propertyName));
            return (T)property.ValueProvider.GetValue(obj);
        }
        throw new JsonException(string.Format("Invalid contract {0}", contract));
    }
}

And now you can do:

var accelDelay = JsonExtensions.GetJsonPropertyValue<long>(MT, "Accel Delay");

If you don't know the type in advance, you can just do:

var accelDelay = JsonExtensions.GetJsonPropertyValue<object>(MT, "Accel Delay");

And if you are using camel casing, do:

var resolver = new CamelCasePropertyNamesContractResolver();
var accelDelay = JsonExtensions.GetJsonPropertyValue<object>(MT, "Accel Delay", resolver);

Notes:

Demo fiddle here.

dbc
  • 104,963
  • 20
  • 228
  • 340
  • 1
    Thanks very much , that answers my question , I needed to set the value too but it was not hard to do a corresponding SetValue methos to go with this GetValue – RogerM Sep 17 '19 at 01:37