如何将JSON字符串反序列化为类似这样的实体(自我跟踪属性被删除为简单):
public class User:
{
int Id { get; set; }
string Name { get; set; }
public TrackableCollection<Role> Roles { get; set; } // <!
}
角色也是具有两个属性的简单类。 TrackableCollection是Collection(System.Collections.ObjectModel)的后代。
所以我想:拥有像这样的JSON字符串
{"Id":0, "Name":"Test User", "Roles": [{"Id":1, "Name": "Role 1"}, {"Id":2, "Name": "Role 2"}, {"Id":3, "Name": "Role 3"}]}
使用正确反序列化的Roles集合获取实体。
答案 0 :(得分:1)
好的,似乎没有人对此问题感兴趣,无论如何这里是解决方案。此类序列化和反序列化自跟踪POCO实体,包括所有嵌套的TrackableCollections和对象。
请注意 SupportedTypes 方法。我添加了 IEntity 界面(内部空白)并在此行修改了我的T4模板:
<#=Accessibility.ForType(entity)#> <#=code.SpaceAfter(code.AbstractOption(entity))#>partial class <#=code.Escape(entity)#><#=code.StringBefore(" : ", code.Escape(entity.BaseType))#><#=(entity.BaseType == null ? ": " : ", ") + "IEntity" #>, IObjectWithChangeTracker, INotifyPropertyChanged
你对IEntity无能为力。只需根据需要编写 SupportedTypes 方法。
我还评论了ChangeTracker属性上方模板中的 [DataMember] 属性:
//[DataMember]
public ObjectChangeTracker ChangeTracker
无论如何这并不重要。拿EntityConverter享受。
/// <summary>
/// Serializes self-tracking POCO entities with DataMemberAttribute marked properties.
/// </summary>
public class EntityConverter : JavaScriptConverter
{
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (obj != null)
{
var properties = obj.GetType().GetProperties().Where(prop => prop.HasAttibute(typeof(DataMemberAttribute)));
foreach (var property in properties)
{
object value = property.GetValue(obj, null);
// Serialize nested TrackableCollection object
if (property.PropertyType.Name.Equals(typeof(TrackableCollection<object>).Name))
value = SerializeCollection((value as IEnumerable).Cast<object>(), serializer);
result.Add(property.Name, value);
}
}
return result;
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
var entity = Activator.CreateInstance(type);
foreach (KeyValuePair<string, object> kvp in dictionary)
{
PropertyInfo property = type.GetProperty(kvp.Key);
if ((property != null) && (property.HasAttibute(typeof(DataMemberAttribute))))
{
object value = default(object);
if (!property.PropertyType.Name.Equals(typeof(TrackableCollection<object>).Name))
{
// If property is not a TrackableCollection object
// http://stackoverflow.com/questions/793714/how-can-i-fix-this-up-to-do-generic-conversion-to-nullablet
Type u = Nullable.GetUnderlyingType(property.PropertyType);
string jsonValue = kvp.Value != null ? kvp.Value.ToString() : null;
dynamic dynamicVal;
if (u != null)
dynamicVal = jsonValue == "null" ? null : Convert.ChangeType(jsonValue, u);
else if (kvp.Value is IDictionary<string, object>)
dynamicVal = Deserialize(kvp.Value as IDictionary<string, object>, property.PropertyType, serializer);
else
dynamicVal = Convert.ChangeType(jsonValue, property.PropertyType);
value = dynamicVal;
}
else
{
// If property is a TrackableCollection object
var dictionaries = (kvp.Value as IEnumerable).Cast<IDictionary<string, object>>();
value = DeserializeCollection(dictionaries, property.PropertyType, serializer);
}
property.SetValue(entity, value, null);
}
}
return entity;
}
/// <summary>
/// Serializes TrackableCollection
/// </summary>
protected IList<IDictionary<string, object>> SerializeCollection(IEnumerable<object> collection, JavaScriptSerializer serializer)
{
var result = new List<IDictionary<string, object>>();
foreach (object obj in collection)
{
result.Add(Serialize(obj, serializer));
}
return result;
}
/// <summary>
/// Deserializes TrackableCollection
/// </summary>
protected object DeserializeCollection(IEnumerable<IDictionary<string, object>> dictionaries, Type propertyType, JavaScriptSerializer serializer)
{
object collection = Activator.CreateInstance(propertyType); // TrackableCollection<T>
Type genericType = propertyType.GetGenericArguments()[0]; // T
MethodInfo addMethod = collection.GetType().GetMethod("Add"); // Add(T object)
foreach (var dic in dictionaries)
{
addMethod.Invoke(collection, new [] { Deserialize(dic, genericType, serializer) });
}
return collection;
}
/// <remarks>
/// http://stackoverflow.com/questions/159704/how-to-implement-custom-json-serialization-from-asp-net-web-service
/// </remarks>
public override IEnumerable<Type> SupportedTypes
{
get
{
IList<Type> result = new List<Type>();
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
AssemblyBuilder dynamicAssemblyCheck = assembly as AssemblyBuilder;
if (dynamicAssemblyCheck == null)
{
try
{
foreach (Type type in assembly.GetExportedTypes())
{
if ((type != typeof(IEntity)) && typeof(IEntity).IsAssignableFrom(type))
{
result.Add(type);
}
}
}
catch(Exception){} // bad practice, i know, i know
}
}
return result;
}
}
}