0

如何将 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"}]}

获取具有正确反序列化角色集合的实体。

4

1 回答 1

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;
        }
    }
}
于 2010-12-28T06:18:01.120 回答