我使用Azure使用数据库优先EF方法。 Azure Web服务中的一个实体定义如下:
public class Company : EntityData
{
public string CompanyName { get; set; }
}
它从EntityData继承Id属性。 Id属性的类型为string。
在客户端,我有以下实体:
class Company
{
[JsonConverter(typeof(IntConverter))]
public int Id { get; set; }
public string CompanyName { get; set; }
}
如上所示,我需要将Id从字符串转换为int。
我创建了以下JSON转换器:
class IntConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}
public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
if (reader.Value == null)
return 0;
int num;
if (Int32.TryParse(reader.Value.ToString(), out num))
return num;
else
return 0;
}
public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{
serializer.Serialize(writer, value.ToString());
}
}
它工作正常,但因为这是我的第一个JSON转换器,我不确定我是否正确创建它。我看到了转换器的例子,他们使用的是existingValue而不是reader.Value。就我而言,existingValue始终为0。
上述实施是否正确?
答案 0 :(得分:0)
您的代码基本正确。
existingValue
是先前存在于父c#模型中的值。通过将其传递到转换器,Json.NET允许转换器在populating现有模型或只读集合时工作。例如,如果您有一个带转换器的预分配只读属性:
public class RootObject
{
readonly ObservableCollection<SomeClass> _collection = new ObservableCollection<SomeClass>();
[JsonConverter(typeof(ObservableCollectionConverter<SomeClass>>)]
public ObservableCollection<SomeClass> { get { return _collection; } }
}
然后,ObservableCollectionConverter<SomeClass>
_collection
方法会传递预先分配的value.ToString()
值,并且可以向其中添加项目。
话虽如此,但仍有一些改进:
在ReadJson()
中,您拨打ToString()
。 public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{
// Int32 implements the IConvertible interface which has a ToString() overload
// that takes an IFormatProvider specification. Pass the invariant format to guarantee
// identical serialization in all cultures.
var convertible = (IConvertible)value;
serializer.Serialize(writer, convertible.ToString(NumberFormatInfo.InvariantInfo));
}
有可能返回特定于文化的字符串,例如可能会为WriteJson()
插入小数点。相反,您应该按照NumberGroupSeparator
序列化,如下所示:
ReadJson()
需要在 int num;
if (Int32.TryParse(reader.Value.ToString(), NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out num))
return num;
else
return 0;
:
ReadJson()
您的{"unexpectedProperty": "unexpectedValue"}
无法抵御意外数据。例如,如果传入的JSON实际上具有数组或对象值(例如JsonReader
),则public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
switch (reader.TokenType)
{
case JsonToken.Null:
return null;
case JsonToken.Integer:
// Input was already an integer. Return it
return (int)JToken.Load(reader);
case JsonToken.String:
{
int num;
if (Int32.TryParse(reader.Value.ToString(), NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out num))
return num;
else
return 0;
}
default:
throw new JsonSerializationException(string.Format("Unexpected token {0} at path {1}", reader.TokenType, reader.Path));
}
将无法正确地前进到输入的末尾。您应该检查invariant format并正确处理错误数据,例如:
default:
Debug.WriteLine(string.Format("Unexpected token {0} at path {1}", reader.TokenType, reader.Path));
reader.Skip();
return 0;
或者,如果您希望在不抛出异常的情况下使用和丢弃意外数据(我不建议这样做),您可以使用reader.TokenType
:
true
JsonReader.Skip()
。但是,如果您将转换器添加到JsonConverter.CanConvert
,那么从CanConvert
返回NotImplementedException
将会出现问题。相反,我建议抛出public override bool CanConvert(Type objectType)
{
return objectType == typeof(int) || objectType == typeof(int?);
}
或正确实施该方法:
class IntConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(int) || objectType == typeof(int?);
}
public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
switch (reader.TokenType)
{
case JsonToken.Null:
return null;
case JsonToken.Integer:
// Input was already an integer. Return it
return (int)JToken.Load(reader);
case JsonToken.String:
{
int num;
if (Int32.TryParse(reader.Value.ToString(), NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out num))
return num;
else
return 0;
}
default:
throw new JsonSerializationException(string.Format("Unexpected token {0} at path {1}", reader.TokenType, reader.Path));
}
}
public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{
// Int32 implements the IConvertible interface which has a ToString() overload
// that takes an IFormatProvider specification. Pass the invariant format to guarantee
// identical serialization in all cultures.
var convertible = (IConvertible)value;
serializer.Serialize(writer, convertible.ToString(NumberFormatInfo.InvariantInfo));
}
}
因此,您的最终转换器可能如下所示:
{{1}}
样本JsonSerializerSettings.Converters
显示最终转换器的严格和容忍版本。