-1

What would be the best approach for having a class with two distinct fields (with distinct types) but same PropertyName. It will always be the case that whenever one of the fields has a value, the other one will be null. I know I could create two different classes, each of them with only one field. Is there a better alternative than creating two different classes?

Here's an example of what I'm trying to accomplish:

[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class Foo
{
    private Foo(int x, bool asAList = false)
    {
        if (asAList)
        {
            Baz = new List<int> { x };
        }
        else
        {
            Bar = x;
        }
    }

    public static JObject Get(int x, bool asAList = false)
    {
        Foo foo = new Foo(x, asAList);
        return JObject.FromObject(foo);
    }

    [JsonProperty(PropertyName = "qwerty", NullValueHandling = NullValueHandling.Ignore)]
    public int? Bar { get; set; } = null;

    [JsonProperty(PropertyName = "qwerty", NullValueHandling = NullValueHandling.Ignore)]
    public List<int> Baz { get; set; } = null;
}

And I'd like to be able to do this:

JObject a = Foo.Get(1);
JObject b = Foo.Get(2, true);
Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
  • 1
    Are the two properties really *completely* different types or is it just that one is a single item and the other is a list of the same? If the latter, you could just declare one property (the list) and then use the `SingleOrArrayConverter` class from [How to handle both a single item and an array for the same property using JSON.net](https://stackoverflow.com/q/18994685/10263) to solve this problem. – Brian Rogers Oct 15 '18 at 01:50

1 Answers1

1

You could have one private JToken JsonProperty that is being used for serializing/deserializing to either of the two public facing properties. On a set operation, that would then determine based on the JToken type if it's a JArray or not and then based on that determine which of the other properties to set. On a get operation, it would use the property that isn't null and convert that to the JToken. In order to deserialize you'll want a constructor that can be used the [JsonConstructor] can be added. Since you don't want to serialize/deserialize the other properties directly, the [JsonProperty] attribute can be removed because of the MemberSerialization.OptIn.

[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class Foo
{
    [JsonConstructor]
    private Foo()
    { }

    private Foo(int x, bool asAList = false)
    {
        if (asAList)
            Baz = new List<int> { x };
        else
            Bar = x;
    }

    public static JObject Get(int x, bool asAList = false)
    {
        Foo foo = new Foo(x, asAList);
        return JObject.FromObject(foo);
    }

    [JsonProperty(PropertyName = "qwerty", NullValueHandling = NullValueHandling.Ignore)]
    private JToken Qwerty
    {
        get
        {
            return Bar.HasValue ? JToken.FromObject(Bar) : Baz != null ? JToken.FromObject(Baz) : null;
        }
        set
        {
            if (value != null && value.Type == JTokenType.Array)
                Baz = value?.ToObject<List<int>>();
            else
                Bar = value?.ToObject<int?>();
        }
    }

    public int? Bar { get; set; }

    public List<int> Baz { get; set; }
}
C. Mitchell
  • 176
  • 7