使用嵌套 TrackableCollection 反序列化自跟踪实体

发布于 2024-09-27 23:03:51 字数 524 浏览 2 评论 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"}]}

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

How can I deserialize JSON string into entity of type like this (self-tracking properties removed to be simple):

public class User: 
{
    int Id { get; set; }
    string Name { get; set; }
    public TrackableCollection<Role> Roles { get; set; } // <!
}

Role is also simple class with two properties. TrackableCollection is descendant of Collection (System.Collections.ObjectModel).

So I want: having JSON string like this

{"Id":0, "Name":"Test User", "Roles": [{"Id":1, "Name": "Role 1"}, {"Id":2, "Name": "Role 2"}, {"Id":3, "Name": "Role 3"}]}

get entity with correctly deserialized Roles collection.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

爱给你人给你 2024-10-04 23:03:51

好吧,似乎没有人对这个问题感兴趣,无论如何,这是解决方案。此类序列化和反序列化自跟踪 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;
        }
    }
}

Ok, seems like nobody was interested this question, anyway here is the solution. This class serializes and deserializes self-tracking POCO entities including all nested TrackableCollections and objects.

Please notice about SupportedTypes method. I added the IEntity interface (blank inside) and modified my T4 template on this line:

<#=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

You can do nothing about IEntity. Just write the SupportedTypes method as you need.

I also commented the [DataMember] attribute in the template above the ChangeTracker property:

//[DataMember]
public ObjectChangeTracker ChangeTracker

Anyway this is not important. Take the EntityConverter and enjoy.

/// <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;
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文