最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - How to make Deserialization work with a private field? - Stack Overflow

programmeradmin2浏览0评论

I'm wanting to only expose a list as ReadOnly but it's, but while trying to accomodate that for Deserialization, it's not currently working.

Firstly, to confirm Serialization:

{
  "StartTime": {
    "WeightedValues": [
      {
        "Value": "6",
        "Weight": 1.0
      },
      {
        "Value": "7",
        "Weight": 1.0
      }
    ]
  },
}

This code, with a public List works for both serialization and deserialzation:

 internal class PoSet<T>
 {
     public List<PossibleOutcome<T>> WeightedValues = new();

     public PoSet() { }

     public PoSet(IEnumerable<PossibleOutcome<T>> weightedValues)
     {
         if (weightedValues == null)
             throw new ArgumentNullException(nameof(weightedValues));

         WeightedValues.AddRange(weightedValues);
     }

     public void Add(PossibleOutcome<T> weightedValue)
     {
         if (weightedValue == null)
             throw new ArgumentNullException(nameof(weightedValue));

         WeightedValues.Add(weightedValue);
     }
 }

...but this code, which exposes just a ReadOnly list and uses a JSON Constructor attribute doesn't works for Serialization but not for Deserialization. I've tried a couple of JSON attribute variations:

internal class PoSet<T>
   {
       private List<PossibleOutcome<T>> _weightedValues = new();

       public IReadOnlyList<PossibleOutcome<T>> WeightedValues => _weightedValues.AsReadOnly();

       [JsonConstructor]
       public PoSet(List<PossibleOutcome<T>> weightedValues) //Constructor for the deserializer
       {
           if (weightedValues == null)
               throw new ArgumentNullException(nameof(weightedValues));
           _weightedValues.AddRange(weightedValues);
       }

       public PoSet() { }

       public PoSet(IEnumerable<PossibleOutcome<T>> weightedValues)
       {
           if (weightedValues == null)
               throw new ArgumentNullException(nameof(weightedValues));
           _weightedValues.AddRange(weightedValues);
       }

       public void Add(PossibleOutcome<T> weightedValue)
       {
           if (weightedValue == null)
               throw new ArgumentNullException(nameof(weightedValue));
           _weightedValues.Add(weightedValue);
       }
   }

Any help much appreciated. Surely this is possible. I've read a little about contracts but that seems beyond my abilities (this is hobby stuff; I'm not a real programmer).

BTW If it helps, this is the PossibleOutcome class:

// Generic WeightedValue class (for any type T)
internal  class PossibleOutcome<T>
{
    public T Value { get; set; }
    public double Weight { get; set; }

    public PossibleOutcome() { } // Parameterless constructor for deserialization

    public PossibleOutcome(T value, double weight)
    {
        if (weight < 0)
            throw new ArgumentException("Weight cannot be negative.", nameof(weight));

        Value = value;
        Weight = weight;
    }
}

I'm wanting to only expose a list as ReadOnly but it's, but while trying to accomodate that for Deserialization, it's not currently working.

Firstly, to confirm Serialization:

{
  "StartTime": {
    "WeightedValues": [
      {
        "Value": "6",
        "Weight": 1.0
      },
      {
        "Value": "7",
        "Weight": 1.0
      }
    ]
  },
}

This code, with a public List works for both serialization and deserialzation:

 internal class PoSet<T>
 {
     public List<PossibleOutcome<T>> WeightedValues = new();

     public PoSet() { }

     public PoSet(IEnumerable<PossibleOutcome<T>> weightedValues)
     {
         if (weightedValues == null)
             throw new ArgumentNullException(nameof(weightedValues));

         WeightedValues.AddRange(weightedValues);
     }

     public void Add(PossibleOutcome<T> weightedValue)
     {
         if (weightedValue == null)
             throw new ArgumentNullException(nameof(weightedValue));

         WeightedValues.Add(weightedValue);
     }
 }

...but this code, which exposes just a ReadOnly list and uses a JSON Constructor attribute doesn't works for Serialization but not for Deserialization. I've tried a couple of JSON attribute variations:

internal class PoSet<T>
   {
       private List<PossibleOutcome<T>> _weightedValues = new();

       public IReadOnlyList<PossibleOutcome<T>> WeightedValues => _weightedValues.AsReadOnly();

       [JsonConstructor]
       public PoSet(List<PossibleOutcome<T>> weightedValues) //Constructor for the deserializer
       {
           if (weightedValues == null)
               throw new ArgumentNullException(nameof(weightedValues));
           _weightedValues.AddRange(weightedValues);
       }

       public PoSet() { }

       public PoSet(IEnumerable<PossibleOutcome<T>> weightedValues)
       {
           if (weightedValues == null)
               throw new ArgumentNullException(nameof(weightedValues));
           _weightedValues.AddRange(weightedValues);
       }

       public void Add(PossibleOutcome<T> weightedValue)
       {
           if (weightedValue == null)
               throw new ArgumentNullException(nameof(weightedValue));
           _weightedValues.Add(weightedValue);
       }
   }

Any help much appreciated. Surely this is possible. I've read a little about contracts but that seems beyond my abilities (this is hobby stuff; I'm not a real programmer).

BTW If it helps, this is the PossibleOutcome class:

// Generic WeightedValue class (for any type T)
internal  class PossibleOutcome<T>
{
    public T Value { get; set; }
    public double Weight { get; set; }

    public PossibleOutcome() { } // Parameterless constructor for deserialization

    public PossibleOutcome(T value, double weight)
    {
        if (weight < 0)
            throw new ArgumentException("Weight cannot be negative.", nameof(weight));

        Value = value;
        Weight = weight;
    }
}
Share Improve this question edited Mar 19 at 6:42 DarkBee 15.5k8 gold badges72 silver badges117 bronze badges asked Mar 19 at 3:34 MrGregglesMrGreggles 6,17510 gold badges43 silver badges52 bronze badges 2
  • 1 It would be helpful to know which JSON library you're using. – ProgrammingLlama Commented Mar 19 at 3:57
  • Nothing special: using System.Text.Json.Serialization; in .NET – MrGreggles Commented Mar 19 at 6:04
Add a comment  | 

1 Answer 1

Reset to default 3

I think the library you are using is System.Text.Json because Json.Net can deserialize this class normally. The JsonConstructor rule of System.Text.Json is somewhat wooden, it requires that each parameter must be able to match a property (or field), their names and types must be consistent (name is case-insensitive), so you need to change the parameter type to IReadOnlyList<PossibleOutcome<T>>.

发布评论

评论列表(0)

  1. 暂无评论