我有一个这样的物理尺寸类:
public class Physical
{
public Dimension Dimension {get; set;}
public double Value {get; set;}
public string Unit {get; set;}
}
Dimension
是一个枚举,其值包含Force
,Temperature
,Displacement
,Time
等。
和一个具有Physical
属性的类,例如
public class MeasurementInfo
{
public Instrument Instrument {get; set;}
public Physical MaxReading {get; set;}
public Physical MinReading {get; set;}
public Physical AmbientTemperature {get; set;}
}
Instrument
也是一个具有Chronometer
,WeightScale
,Thermometer
,Caliper
等值的枚举。
我的某些Dimension
属性的Physical
属性值取决于Instrument
值。其他的是固定的。示例:
var myMeasure = new MeasurementInfo()
{
Instrument = Instrument.WeightScale,
MaxReading = new Physical()
{
Dimension = Dimension.Weight,
Value = 100.0,
Unit = "kg"
},
MinReading = new Physical()
{
Dimension = Dimension.Weight,
Value = 50.0,
Unit = "kg"
},
AmbientTemperature = new Physical()
{
Dimension = Dimension.Temperature,
Value = 27,
Unit = "°C"
}
};
我想要的是将此对象另存为JSON:
{
"Instrument": "Weight Scale",
"Max Reading": "100 kg",
"Min Reading": "50 kg",
"AmbientTemperature": "27 °C"
}
序列化很容易,因为我们定义了Value
和Unit
。我的问题是反序列化,因为我必须读取Instrument
值以确定一个Dimension
才能重新创建Physical
对象。
我的实际尝试是使用ContractResolver
。这样,我可以根据属性类型和名称来定义我的JsonConverter
。
public class MyContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty result = base.CreateProperty(member, memberSerialization);
if(result.PropertyType == typeof(Physical))
{
var property = member as PropertyInfo;
switch (result.PropertyName)
{
case "AmbientTemperature":
result.Converter = new JsonPhysicalConverter(Dimension.Temperature);
break;
case "MaxReading":
case "MinReading":
result.Converter = new JsonPhysicalConverter(???);
break;
}
}
}
}
???是我卡住的地方。 ContractResolver
在实例中不起作用,因此我无法事先知道我的Instrument
值。
答案 0 :(得分:1)
JsonConverter
无权访问其正在处理的对象的父级。因此,如果转换器处理Physical
,它将无法“看到” Instrument
内部的MeasurementInfo
。
所以我可以看到两种方法:
MeasurementInfo
之外的父Physical
。然后,转换器将能够看到Instrument
并根据需要创建Physical
。Dimension
。例如,如果单位为kg
,则您知道尺寸必须为Weight
,而与仪器无关,对吗?仅当有两个外观相同但代表不同尺寸的单元(取决于仪器)时,这种情况才会崩溃。但是根据您的示例,我认为情况并非如此。我认为这种方法会“更清洁”。以下是第一种方法的示例:
public class MeasurementInfoConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(MeasurementInfo);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject obj = JObject.Load(reader);
MeasurementInfo info = new MeasurementInfo();
info.Instrument = obj["Instrument"].ToObject<Instrument>(serializer);
info.MinReading = ReadPhysical(obj, "Min Reading", info.Instrument);
info.MaxReading = ReadPhysical(obj, "Max Reading", info.Instrument);
info.AmbientTemperature = ReadPhysical(obj, "Ambient Temperature", Instrument.Thermometer);
return info;
}
private Physical ReadPhysical(JObject obj, string name, Instrument instrument)
{
Dimension dim = Dimension.Force;
switch (instrument)
{
case Instrument.WeightScale: dim = Dimension.Weight; break;
case Instrument.Chronometer: dim = Dimension.Time; break;
case Instrument.Thermometer: dim = Dimension.Temperature; break;
case Instrument.Caliper: dim = Dimension.Displacement; break;
}
string[] parts = ((string)obj[name]).Split(new char[] { ' ' }, 2);
Physical physical = new Physical()
{
Dimension = dim,
Value = double.Parse(parts[0]),
Unit = parts[1]
};
return physical;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
MeasurementInfo info = (MeasurementInfo)value;
JObject obj = new JObject();
obj.Add("Instrument", JToken.FromObject(info.Instrument, serializer));
WritePhysical(obj, "Min Reading", info.MinReading);
WritePhysical(obj, "Max Reading", info.MaxReading);
WritePhysical(obj, "Ambient Temperature", info.AmbientTemperature);
obj.WriteTo(writer);
}
private void WritePhysical(JObject obj, string name, Physical physical)
{
obj.Add(name, physical.Value.ToString("N0") + " " + physical.Unit);
}
}
往返演示:https://dotnetfiddle.net/ZUibQ1
为完整起见,这是第二种方法的示例:
public class PhysicalConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Physical);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
string value = (string)reader.Value;
string[] parts = value.Split(new char[] { ' ' }, 2);
Dimension dim;
if (!DimensionsByUnit.TryGetValue(parts[1], out dim)) dim = Dimension.Force;
Physical physical = new Physical()
{
Dimension = dim,
Value = double.Parse(parts[0]),
Unit = parts[1]
};
return physical;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Physical physical = (Physical)value;
writer.WriteValue(physical.Value.ToString("N0") + " " + physical.Unit);
}
private static Dictionary<string, Dimension> DimensionsByUnit = new Dictionary<string, Dimension>
{
{ "mg", Dimension.Weight },
{ "g", Dimension.Weight },
{ "kg", Dimension.Weight },
{ "°C", Dimension.Temperature },
{ "°F", Dimension.Temperature },
{ "°K", Dimension.Temperature },
{ "µs", Dimension.Time },
{ "ms", Dimension.Time },
{ "s", Dimension.Time },
{ "mm", Dimension.Displacement },
{ "cm", Dimension.Displacement },
{ "m", Dimension.Displacement },
};
}
答案 1 :(得分:0)
使用匿名对象:
var objectToBeSerialized = new
{
Instrument = myMeasure.Instrument.ToString(),
MaxReading = $"{myMeasure.MaxReading.Value} {myMeasure.MaxReading.Unit}",
MinReading = $"{myMeasure.MinReading.Value} {myMeasure.MinReading.Unit}"
};
,然后使用NewtonSoft.Json库将此对象转换为JSON:
var serializedJSON = JsonConvert.SerializeObject(objectToBeSerialized);