【问题标题】:c# JavaScriptConverter - how to deserialize custom property?c# JavaScriptConverter - 如何反序列化自定义属性?
【发布时间】:2011-12-23 13:21:59
【问题描述】:

我有一个已序列化为 JSON 的类,我正在尝试将其反序列化为一个对象。

例如

public class ContentItemViewModel
{
    public string CssClass { get; set; }
    public MyCustomClass PropertyB { get; set; }
}

简单属性 (CssClass) 将反序列化:

 var contentItemViewModels = ser.Deserialize<ContentItemViewModel>(contentItems);

但是 PropertyB 出错了...

我们添加了一个 JavaScriptConverter:

  ser.RegisterConverters(new List<JavaScriptConverter>{ publishedStatusResolver});

但是当我们将“MyCustomClass”添加为“SupportedType”时,从未调用过 Deserialize 方法。但是,当我们将 ContentItemViewModel 作为 SupportedType 时,就会调用 Deserialize。

我们有一个看起来像这样的当前解决方案:

class ContentItemViewModelConverter : JavaScriptConverter
{

    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        var cssClass =  GetString(dictionary, "cssClass"); //I'm ommitting the GetString method in this example...           
        var propertyB= GetString(dictionary, "propertyB");

        return new ContentItemViewModel{    CssClass = cssClass , 
                                            PropertyB = new MyCustomClass(propertyB)}
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        throw new Exception("Only does the Deserialize");
    }

    public override IEnumerable<Type> SupportedTypes
    {
        get
        {
            return new List<Type>
                {
                    typeof(ContentItemViewModel)
                };
        }
    }
}

但我们更喜欢仅反序列化 MyCustomClass 的更简单的解决方案,因为 ViewModel 上还有许多其他字段,每次更改/添加属性时都必须编辑此转换器似乎很浪费。 ...

有没有办法反序列化 MyCustomClass 类型的 JUST PropertyB?

感谢您的帮助!

【问题讨论】:

    标签: c# javascript json serialization


    【解决方案1】:

    您是否考虑过使用DatacontractJsonSerializer

    [DataContract]
    public class MyCustomClass
    {
        [DataMember]
        public string foobar { get; set; }
    }
    
    [DataContract]
    public class ContentItemViewModel
    {
        [DataMember]
        public string CssClass { get; set; }
        [DataMember]
        public MyCustomClass PropertyB { get; set; }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
    
            ContentItemViewModel model = new ContentItemViewModel();
            model.CssClass = "StackOver";
            model.PropertyB = new MyCustomClass();
            model.PropertyB.foobar = "Flow";
    
            //Create a stream to serialize the object to.
            MemoryStream ms = new MemoryStream();
    
            // Serializer the User object to the stream.
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(ContentItemViewModel));
            ser.WriteObject(ms, model);
            byte[] json = ms.ToArray();
            ms.Close();
            string s=  Encoding.UTF8.GetString(json, 0, json.Length);
    
    
            Console.ReadLine();
        }
    }
    

    如果 MyCustomClass 有派生,则将所有可能的类添加到 DatacontractJsonSerializer.KnownTypes

    【讨论】:

      【解决方案2】:

      不管它是否值得,但我偶然发现了同样的问题,解决方案是反序列化器不知道你正在反序列化的类,除非你给他必要的信息。

      在顶层,它从 Deserialize() 的类型参数中知道类型。这就是您的ContentItemViewModel 转换器工作的原因。对于嵌套对象,它需要 __type 属性和 JavaScriptTypeResolver。

      var ser = new JavaScriptSerializer(new SimpleTypeResolver());
      ser.RegisterConverters(myconverters);
      MyClass myObject = new MyClass();
      string json = ser.Serialize(myObject);
          // set a breakpoint here to see what has happened
      ser.Deserialize<MyClass>(json);
      

      TypeResolver 为每个序列化对象添加一个 __type 属性。您可以编写使用短名称的自定义类型解析器。在这个示例中,我使用了来自 .net 的 SimpleTypeResolver,它“简单地”将完全限定的类型名称存储为 __type。反序列化时,JavaScriptDeserializer 找到 __type 并向 TypeResolver 询问正确的类型。然后它知道一个类型并且可以调用一个注册的 JavaScriptConverter.Deserialize 方法。

      如果没有 TypeResolver,对象会被反序列化为 Dictionary,因为 JavaScriptSerializer 没有任何类型信息。

      如果您无法在 json 字符串中提供 __type 属性,我认为您需要先反序列化到 Dictionary 然后添加一个“猜测步骤”来解释字段以找到正确的类型。然后,您可以使用 JavaScriptSerializer 的 ConvertToType 方法将字典复制到对象的字段和属性中。

      如果您需要使用 ASP.NET 提供的 JavaScriptSerializer 而无法自己创建,请参考 JavaScriptSerializer 的 .ctor 帮助中的这一部分:

      异步通信层用于从客户端脚本调用 Web 服务的 JavaScriptSerializer 实例使用特殊类型的解析器。此类型解析器将可以反序列化的类型限制为在 Web 服务的方法签名中定义的类型,或者应用了 GenerateScriptTypeAttribute 的类型。您不能以编程方式修改此内置类型解析器。

      也许 GenerateScriptType 属性可以帮助你。但是不知道这里需要什么样的__type属性。

      【讨论】:

        猜你喜欢
        • 2015-11-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-27
        • 2014-08-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多