0

So, I try to deserialize JSON file that has a format

"farmableitem": [
      {
        "@uniquename": "T1_FARM_CARROT_SEED",
        "@tier": "1",
        "@kind": "plant",
        "@weight": "0.1",
        "harvest": {
          "@growtime": "79200",
          "@lootlist": "T1_CARROT_LOOT",
          "@lootchance": "1",
          "@fame": "100",
          "seed": {
            "@chance": "0.0000",
            "@amount": "1"
          }
        }
      },      
      {
        "@uniquename": "T5_FARM_OX_BABY",
        "@tier": "5",
        "@kind": "animal",
        "@weight": "1.5",
        "grownitem": {
          "@uniquename": "T5_FARM_OX_GROWN",
          "@growtime": "504000",
          "@fame": "300",
          "offspring": {
            "@chance": "0.7867",
            "@amount": "1"
          }
        }
]

As you can see, "harvest" and "grownitem", as well as, "seed" and "offspring" are basically the same... So there is no reason for me to create two different classes.

I know that if you want to give a specific field two different PropertyNames you can do the next:

    [JsonProperty("first")]
    public string Test { get; set; }
    [JsonProperty("second")]
    private string _test { set { Test = value; } }

However, I'm not sure that I can do the same thing for the classes... At least I couldn't find a solution.

So, long story short, I want to have two different JsonPropertyName for one class. Is it possible?

Mekromic
  • 1
  • 1
  • You can either create a base class that contains common properties or you can rename your json structure to use the same name for each common object. The latter is easier. And there is nothing wrong with having a large number of classes if it correctly represents your json structure. – David L Jan 12 '21 at 21:26
  • Only `offspring` and `seed` are the same. The other properties have different properties, not just different names. – Panagiotis Kanavos Jan 12 '21 at 21:26
  • I would create two properties on the object, both `harvest` and `grownitem` that point to the same backing field – Charlieface Jan 12 '21 at 21:29
  • @DavidL wait, what do you mean by renaming json structure? – Mekromic Jan 12 '21 at 21:43
  • @PanagiotisKanavos The name of the properties is the same => the name of the fields in the class will be also the same... It is expectable that properties will have different value – Mekromic Jan 12 '21 at 21:44
  • why is `seed` named seed and `offspring` named offspring in your json? It seems like they could be the same property name and share a common class. – David L Jan 12 '21 at 21:44
  • @Charlieface that's exactly what I was going to do, however, since harvest and grownitem have to be represented as objects, I wasn't sure that creating two classes is the correct solution – Mekromic Jan 12 '21 at 21:46
  • @DavidL oh, I got it. By renaming json structure you mean changing property names in the json? I can't change them.... well, I can but it would be troublesome since I'm taking json file from API and I can't change it without storing somewhere on my device. – Mekromic Jan 12 '21 at 21:48
  • Makes sense. Sometimes you can control it but if you can't (or can't easily), you'll probably run into fewer headaches by simply creating as many classes as are necessary to represent the json. – David L Jan 12 '21 at 21:50
  • Are they guaranteed to never coexist? Then you only need two properties pointing to the same object not two objects. You definitely don't need two classes either way as they have the same structure – Charlieface Jan 12 '21 at 21:50
  • @DavidL They are named like that because game developer that developed game decided so... I, honestly, have no idea what is the reason behind it... Basically they mean the same thing because they both suppose to return an item which is basically "harvesting" – Mekromic Jan 12 '21 at 21:51
  • @Charlieface Yeah, they are guaranteed to never coexist... The idea is that harvesting is related to, for instance, vegetables, while growing is related to animals. – Mekromic Jan 12 '21 at 21:52
  • @Charlieface That exactly what my problem is... I don't know how to point them to the same object – Mekromic Jan 12 '21 at 21:54
  • You could do it with custom getter/setter that point to the same backing field. But looking at it, I think these are actually different enough concepts in the JSON to demand different classes and properties – Charlieface Jan 12 '21 at 21:55
  • @Mekromic the names are definitely not the same. `lootlist` is definitely not the same as `uniquechance`. `lootchance` exists only only on one of these elements. Why do you insist on using the same class to handle such different structures? Creating one more DTO doesn't cost you anything. If *some other* code needs to treat those classes the same, you need to modify that other code. Perhaps implementing an interface on both DTOs with the common properties will be enough. Or you may need to map the DTOs to something else, eg with AutoMapper – Panagiotis Kanavos Jan 13 '21 at 07:47

1 Answers1

0

Long story short... I fixed it, however, my solution looks like a F*** Band-Aid... So, if you have any suggestions on how I can optimize the snippet that I've written, I would really appreciate your help!

        public class Item {
            [JsonProperty(PropertyName = "@uniquename")]
            public string UniqueName { get; set; }

            [JsonProperty(PropertyName = "@tier")]
            public string Tier { get; set; }

            [JsonProperty(PropertyName = "@weight")]
            public string Weight { get; set; }

            [JsonProperty(PropertyName = "@shopcategory")]
            public string Category { get; set; }

            [JsonProperty(PropertyName = "@shopsubcategory1")]
            public string SubCategory { get; set; }
        }

        public class FarmableItem : Item
        {
            [JsonProperty(PropertyName = "@kind")]
            public string Kind { get; set; }

            private class HarvestModel
            {
                [JsonProperty(PropertyName = "@growtime")]
                public string GrowTime { get; set; }

                [JsonProperty(PropertyName = "@lootlist")]
                public string UniqueName { get; set; }

                [JsonProperty(PropertyName = "@fame")]
                public string Fame { get; set; }    

                public class HarvestedItemModel
                {
                    [JsonProperty(PropertyName = "@chance")]
                    public string SuccessRate { get; set; }

                    [JsonProperty(PropertyName = "@amount")]
                    public string Amount { get; set; }
                }

                public class GrownItemModel : HarvestedItemModel {}

                [JsonProperty(PropertyName = "seed")]
                public HarvestedItemModel HarvestedItem = new HarvestedItemModel();

                [JsonProperty(PropertyName = "offspring")]
                public GrownItemModel GrownItem = new GrownItemModel();

            }

            private class GrowModel : HarvestModel {}

            [JsonProperty("harvest")]
            private HarvestModel Harvest = new HarvestModel();

            [JsonProperty("grownitem")]
            private GrowModel Grow = new GrowModel();

            public string GrowTime => Harvest.UniqueName == null ? Grow.GrowTime : Harvest.GrowTime;
            public string Loot => Harvest.UniqueName == null ? Grow.UniqueName : Harvest.UniqueName;
            public string Fame => Harvest.UniqueName == null ? Grow.Fame : Harvest.Fame;

            public string SuccessChance => Harvest.UniqueName == null ? Grow.GrownItem.SuccessRate : Harvest.HarvestedItem.SuccessRate;
            public string Amount => Harvest.UniqueName == null ? Grow.GrownItem.Amount : Harvest.HarvestedItem.Amount;
        }

My logic => UniqueName always exists, so we can use it as a test to differentiate between "harvest" and "grownitem", and since "seed" and "offspring" corresponds to "harvest" and "grownitem" consequently, we can also use it to check for "seed" and "offspring".

Mekromic
  • 1
  • 1
  • If you have to go to such trouble, it's a clear indicator that the tool is used in the wrong way. Like using a hammer to drive a screw. It's possible but a lot harder, and the result is ugly – Panagiotis Kanavos Jan 13 '21 at 07:44
  • As for band aids, I suspect the real band aid is the original idea of using the same class to tread different payload. When that didn't work you posted a question about the Band Aid, not the actual problem. This is called [the XY Problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) – Panagiotis Kanavos Jan 13 '21 at 07:50