0

I have a class with a field called "productName". I would like to allow an alias ("name") for that field.

Now, I could do it by just adding another field and some logic, but perhaps there's a neater way?

The constructor looks like this at the moment:

  [JsonConstructor]
  public OsInfo(string name = null, string platform = null, string version = null) {

The goal is to accept both of these JSON chunks:

Using "name":

  'os': {
       'platform': 'Android-armv7-a',
       'name': 'Android',
       'version': 'Android 7.1.2'
   }

Using "productname":

  'os': {
       'platform': 'Android-armv7-a',
       'productname': 'Android',
       'version': 'Android 7.1.2'
   }

My current solution looks like this, but I was hoping to find a neater way:

    [JsonConstructor]
    public OsInfo(string name = null, string productname = null, string platform = null, string version = null)
    {
        if (name != null && productname != null)
        {
            throw new ArgumentException("Don't use both aliases for OS name");
        }

        this.Name = name != null ? name : productname;
  • 1
    You can add `[JsonProperty("productName")]` to the constructor parameter `name` as shown in [this answer](https://stackoverflow.com/a/43034838/3744182) to [Json.net `JsonConstructor` constructor parameter names](https://stackoverflow.com/q/43032552/3744182). – dbc Apr 10 '20 at 00:15
  • Nope that won't work. If I do that, I replace "name" as a valid field name rather than add an alias for it. And you can't add two JsonProperty annotations to the same field. – Anders Sewerin Johansen Apr 10 '20 at 00:30
  • 2
    Then maybe you could explain a little more what you are trying to do. Are you trying to rename a constructor parameter, rename a property, map *two names simultaneously* to a constructor parameter, or map *two names simultaneously* to a property? A [mcve] would go a long way to clearing up your requirement. – dbc Apr 10 '20 at 00:34
  • You need to show the actual JSON, the actual code, what you expect and what you are getting including all exception with stack trace. – Jonathan Alfaro Apr 10 '20 at 01:40
  • @JonathanAlfaro There are no exceptions and no stack traces. All I want to do is to allow people to use a (deprecated) key for a value ("productname") as an alias for the correct one ("name"). There is also no "what I expect and what I am getting" as there was no running code. It's not an attempt to fix a bug. It's an attempt to add a feature in the cleanest possible fashion. – Anders Sewerin Johansen Apr 10 '20 at 13:47
  • @dbc Done. I honestly thought is was very clear that I want to map two possible names simultaneously to the same value. After all I did say "alias" in both the question title and body, rather than "rename"... – Anders Sewerin Johansen Apr 10 '20 at 13:49
  • Why do you need a constructor? Could you just have two properties and one of them set the other one? – Jonathan Alfaro Apr 10 '20 at 14:44
  • @JonathanAlfaro because that's how we deserialize in this case. Hence the [JsonConstructor] annotation on the constructor. – Anders Sewerin Johansen Apr 10 '20 at 15:58
  • But you do not need a constructor to deserialize from json.... You only needed if you need to perform custom logic inside the constructor.... But if all you are doing is mapping properties you can just deserialize without a constructor... This would make your life easier... You could add an extra property and the setter would point to the Name property. – Jonathan Alfaro Apr 10 '20 at 16:17
  • @JonathanAlfaro I appreciate the suggestion, but for various reasons this is not a great option for me. – Anders Sewerin Johansen Apr 10 '20 at 16:58
  • If you need to map two different names to the same constructor parameter, adding a constructor with both parameters is going to be the easiest solution. One minor improvement: as long as you mark the constructor with `[JsonConstructor]` you can make it be protected or private. If you were mapping multiple names to a property, you could use [json deserialize from legacy property names](https://stackoverflow.com/q/33155458/3744182), but the solution there won't work for a constructor parameter. – dbc Apr 11 '20 at 14:38

1 Answers1

0

The solution ended up being to do it in the constructor. Some alternatives were mentioned in the comments, and seem like they might suit other use cases better.

[JsonConstructor]
public OsInfo(string name = null, string productname = null, string platform = null, string version = null)
{
    if (name != null && productname != null)
    {
        throw new ArgumentException("Don't use both aliases for OS name");
    }

    this.Name = name != null ? name : productname;