我有一个用作字典键的c#结构。为了使该字典转换为json,我需要将struct序列化为字符串(就像json.net对内置结构一样)。
public struct CreditRating
{
public CreditRating(string json) : this()
{
var levels = json.Split(new[] { '~' }, StringSplitOptions.None);
if (levels.Count() >= 3) Level3 = levels[2];
if (levels.Count() >= 2) Level2 = levels[1];
if (levels.Any()) Level1 = levels[0];
}
public string Level1 { get; set; }
public string Level2 { get; set; }
public string Level3 { get; set; }
public override string ToString()
{
return string.Format("{0}~{1}~{2}", Level1, Level2, Level3);
}
public static CreditRating Parse(string json)
{
return new CreditRating(json);
}
}
我的测试:
var rating = new CreditRating { Level1 = "first", Level2 = "Sergey" };
var ratingJson = JsonConvert.SerializeObject(rating); // {"Level1":"first","Level2":"Sergey","Level3":null}
var rating2 = JsonConvert.DeserializeObject<CreditRating>(ratingJson);
var dict = new Dictionary<CreditRating, double> {{rating, 2d}};
var dictJson = JsonConvert.SerializeObject(dict); //{"first~Sergey~":2.0}
var failingTest = JsonConvert.DeserializeObject<Dictionary<CreditRating, double>>(dictJson);
最后一个语句失败,因为它没有调用我的Parse方法或公共构造函数。 我按照文档进行了操作但无法通过此文件。
答案 0 :(得分:2)
好的,所以在尝试了很多事情之后,这最终有效 - 如果其他人碰到这个:
[DataContract(Namespace = ContractNamespace.Current)]
public class CreditSpreadShiftWithLevels
{
[OnDeserializing]
private void Initialize(StreamingContext ctx)
{
ShiftsByRating = new Dictionary<CreditRating, double>();
}
[DataMember]
public bool SplitByRating { get; set; }
[DataMember]
public double ShiftValue { get; set; }
[DataMember]
[JsonConverter(typeof(CreditRatingDoubleDictionaryConverter))]
public Dictionary<CreditRating, double> ShiftsByRating { get; set; }
//other properties
}
[DataContract(Namespace = ContractNamespace.Current)]
public struct CreditRating
{
public CreditRating(string json): this()
{
var levels = json.Split(new[] { '~' }, StringSplitOptions.None);
var cnt = levels.Length;
if (cnt >= 3) Level3 = levels[2];
if (cnt >= 2) Level2 = levels[1];
if (cnt >= 1) Level1 = levels[0];
}
[DataMember]
public string Level1 { get; set; }
[DataMember]
public string Level2 { get; set; }
[DataMember]
public string Level3 { get; set; }
public override string ToString()
{
return string.Format("{0}~{1}~{2}", Level1, Level2, Level3);
}
}
public class CreditRatingDoubleDictionaryConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var dict = new Dictionary<CreditRating, double>();
while (reader.Read())
{
if (reader.TokenType == JsonToken.PropertyName)
{
string readerValue = reader.Value.ToString();
var cr = new CreditRating(readerValue);
if (reader.Read() && reader.TokenType == JsonToken.Float)
{
var val = Convert.ToDouble(reader.Value);
dict.Add(cr, val);
}
}
if (reader.TokenType == JsonToken.EndObject) return dict;
}
return dict;
}
public override bool CanConvert(Type objectType)
{
return typeof(Dictionary<CreditRating, double>).IsAssignableFrom(objectType);
}
}
简而言之,我为字典(而不是struct)创建了转换器,它给了我悲伤和父类的属性。这使得json.net在反序列化时调用我的自定义逻辑。 库中已经存在一些内容,它使字典序列化在创建字典键时调用struct的ToString(这使得它稍微不一致,因为它不尊重返回路由,即使文档类型暗示它 - {{3} })
有一个痛点,我需要为每个不同类型的字典提供单独的转换器,该字典使用结构作为其密钥,例如
public Dictionary<CreditRating, List<string>> BucketsByRating { get; set; }
需要另一个转换器。 我需要看看是否可以使用泛型来增加重用,但如果我能为结构提供单个转换器,那将会更好,我会拥有所有不同的字典属性。
无论如何,我希望这会有用,并节省一些时间。
感谢所有提出建议的人,非常感谢