在C#代碼中,我希望使用我設計的Int32屬性 - 作爲int,但是當使用Json.NET轉換爲Json時,我希望它們被序列化爲一個URI,所以我不必爲了json輸出而將我的所有模型映射到另一個模型。例如一個simpliflied型號:如何讓Json.NET將Int32轉換爲URI
public class Order
{
public int? AccountID { get; set; }
public int ProductID { get; set; }
public decimal Total { get; set; }
}
我想這是呈現:
{ "accountUri": "/account/123", "productUri": "/product/456", "total": 789.01 }
注意外殼和財產改名發生了變化。
如果帳戶ID爲null,則JSON必須給予這樣的:
{ "productUri": "/product/456", "total": 789.01 }
在C#代碼我仍然想使用屬性,你會正常的INT - 所以我想用INT運算符覆蓋。
我不想在模型屬性上使用屬性,但我很高興爲Int32使用包裝類,並且如果需要的話,不介意在包裝類上使用屬性。
下面的代碼是從回答一個公平的方式,但你得到的要點:
public class Order
{
public AccountIdentifier AccountID { get; set; }
public ProductIdentifier ProductID { get; set; }
public decimal Total { get; set; }
}
public abstract class IdentifierBase
{
private readonly string _uriPrefix;
private int? _value;
protected IdentifierBase(string uriPrefix, int? value)
{
_uriPrefix = uriPrefix;
_value = value;
}
public override string ToString()
{
if (_value.HasValue)
return _uriPrefix + _value.Value;
return null;
}
// insert int operator overrides here.
}
public class AccountIdentifier : IdentifierBase
{
public AccountIdentifier(int? value)
: base("/account/", value)
{
}
}
public class ProductIdentifier : IdentifierBase
{
public ProductIdentifier(int? value)
: base("/product/", value)
{
}
}
[Test]
public void JsonConvert()
{
var order = new Order
{
AccountID = new AccountIdentifier(123),
ProductID = new ProductIdentifier(456),
Total = 789.01M
};
using (var stringWriter = new StringWriter())
{
var writer = new JsonTextWriter(stringWriter) {Formatting = Formatting.None};
var settings = new JsonSerializerSettings();
var serializer = JsonSerializer.Create(settings);
// Camel case the properties.
serializer.ContractResolver = new CamelCasePropertyNamesContractResolver();
serializer.Serialize(writer, order);
writer.Flush();
var json = stringWriter.GetStringBuilder().ToString();
Console.Write(json);
}
}
此輸出:
{"accountID":{},"productID":{},"total":789.01}
三個問題:
怎麼辦我將「accountID」重命名爲「accountUri」(並將「productID」重命名爲「productUri」)?
如何使這些特性與包裝類的ToString值(替換「{}」()的結果?
如何完全刪除屬性時,它的空?
感謝
編輯:儘管這是一個相當大量的工作,寫每個模型它保存寫兩個映射器的轉換器下面是我的概念驗證測試證明:
[TestFixture]
public class MyPoC
{
public class OrderJsonConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteStartObject();
var order = value as Order;
if (order.AccountID.HasValue)
{
writer.WritePropertyName("accountUri");
serializer.Serialize(writer, "/account/" + order.AccountID);
}
writer.WritePropertyName("productUri");
serializer.Serialize(writer, "/product/" + order.ProductID);
writer.WritePropertyName("total");
serializer.Serialize(writer, order.Total);
writer.WriteEndObject();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var order = new Order();
var jsonObject = JObject.Load(reader);
order.AccountID = jsonObject.GetNullableIntFromUri("accountUri");
order.ProductID = jsonObject.GetIntFromUri("productUri");
order.Total = jsonObject["total"].Value<decimal>();
return order;
}
public override bool CanConvert(Type objectType)
{
return typeof(Order).IsAssignableFrom(objectType);
}
}
[Test]
public void JsonConvert_Is_Successful()
{
var order = new Order
{
AccountID = 123,
ProductID = 456,
Total = 789.01M
};
var json = JsonConvert.SerializeObject(order, Formatting.None, new OrderJsonConverter());
Console.WriteLine(json);
var deserialized = JsonConvert.DeserializeObject<Order>(json, new OrderJsonConverter());
Console.WriteLine("AccountID: {0}", deserialized.AccountID);
Console.WriteLine("ProductID: {0}", deserialized.ProductID);
Console.WriteLine("Total: {0}", deserialized.Total);
}
}
}
public static class JObjectExtensions
{
public static int GetIntFromUri(this JObject jsonObject, string propertyName)
{
var id = jsonObject.GetNullableIntFromUri(propertyName);
return id.Value;
}
public static int? GetNullableIntFromUri(this JObject jsonObject, string propertyName)
{
var uri = jsonObject[propertyName].ToObject<string>();
var s = Regex.Replace(uri, @".*/(\d+)$", "$1");
int id;
if (int.TryParse(s, out id))
{
return id;
}
return null;
}
}
OUTPUT:
{"accountUri":"/account/123","productUri":"/product/456","total":789.01}
AccountID: 123
ProductID: 456
Total: 789.01
更多的工作將是驗證URI是正確的,不只是一個通用的「翻錄從URI末尾的ID」。
這裏適當的解決方案是使用適配器模式。雖然它不是技術上的映射,但我懷疑你不會因爲你的陳述而喜歡這個「所以我不必爲了json輸出而將我所有的模型映射到另一個模型」。你也應該查找關注點的分離。老實說,你應該真正重新考慮你對潛在解決方案的立場。你正在走上一條沒有什麼道理和難度的道路(並且會讓其他開發者感到困惑)。你已經完成了使用適配器模式,而不是等待在SO上的答案。 – 2014-08-29 13:56:51
是的,我需要分開我的擔憂...我會考慮使用適配器模式。謝謝。 – mkaj 2014-08-30 00:08:22
我已經添加了一個答案給你一個簡潔的例子。 – 2014-09-03 04:56:21