2016-01-07 37 views
3

根据Json.Net documentation所有IEnumerable类型应该序列化为json数组。Json.Net IEnumerable的序列化与TypeNameHandling = auto

因此,我希望下面的类:

public class MyClass 
{ 
    public IEnumerable<string> Values { get; set; } 
} 

被序列为:

{ 
    "Values": [] 
} 

的问题是,当我使用TypeNameHandling=Auto我得到:

{ 
    "Values": { 
     "$type": "System.String[], mscorlib", 
     "$values": [] 
    } 
} 

我需要TypeNameHandling=Auto其他物业,但我期望IEnumerable你默认序列化。其他类型(例如IList)按预期工作。

这是一个错误还是我错过了什么?

[Test] 
    public void Newtonsoft_serialize_list_and_enumerable() 
    { 
     var target = new Newtonsoft.Json.JsonSerializer 
     { 
      TypeNameHandling = TypeNameHandling.Auto 
     }; 

     var myEvent = new MyClass 
     { 
      Values = new string[0] 
     }; 

     var builder = new StringWriter(); 
     target.Serialize(builder, myEvent); 
     var json = JObject.Parse(builder.ToString()); 

     Assert.AreEqual(JTokenType.Array, json["Values"].Type); 
    } 

    public class MyClass 
    { 
     public IEnumerable<string> Values { get; set; } 
    } 

我使用Newtonsoft 7.0.1:

这里的全部代码重现该问题。

UPDATE: 这里使用更多类型的另一项测试:

[Test] 
    public void Newtonsoft_serialize_list_and_enumerable() 
    { 
     var target = new Newtonsoft.Json.JsonSerializer 
     { 
      TypeNameHandling = TypeNameHandling.Auto 
     }; 

     var myEvent = new MyClass 
     { 
      Values1 = new string[0], 
      Values2 = new List<string>(), 
      Values3 = new string[0], 
      Values4 = new List<string>(), 
      Values5 = new string[0] 
     }; 

     var builder = new StringWriter(); 
     target.Serialize(builder, myEvent); 
     var json = builder.ToString(); 
    } 

    public class MyClass 
    { 
     public IEnumerable<string> Values1 { get; set; } 
     public IEnumerable<string> Values2 { get; set; } 
     public IList<string> Values3 { get; set; } 
     public IList<string> Values4 { get; set; } 
     public string[] Values5 { get; set; } 
    } 

这是结果:

{ 
    "Values1": { 
     "$type": "System.String[], mscorlib", 
     "$values": [] 
    }, 
    "Values2": [], 
    "Values3": { 
     "$type": "System.String[], mscorlib", 
     "$values": [] 
    }, 
    "Values4": [], 
    "Values5": [] 
} 

同样,我不明白为什么我得到这取决于不同的结果组合。

回答

3

Json.Net的默认自动行为是在反序列化到IEnumerableIList字段时创建List实例。如果您指定Array实例,那么将对象恢复为原始实例状态的唯一方法是让Json.Net添加$type元数据,这就是您所看到的。 即有很多方法可以反序列化到IEnumerable字段。

通过使用List<string>实例:

var myEvent = new MyClass 
{ 
    Values = new List<string>(), 
}; 

有:

public class MyClass 
{ 
    public IEnumerable<string> Values { get; set; } 
}  

结果(连载时):

{"Values":["hello"]} 

另外,如果你使用显式施工的类型或者使用默认的List,那么Json.Net会使用这个和omit $type;

例如:

string[] Values { get; set; } = new string[0]; // not needed 
IEnumerable<string> Values { get; set; } = new string[0]; //$type needed 
IEnumerable<string> Values { get; set; } = new Stack<string>(); //$type needed 
IEnumerable<string> Values { get; set; } = new List<string>; // not needed 
List<string> Values { get; set; } = new List<string>; // not needed 

ObservableCollection<string> Values { get; set; } = 
    new ObservableCollection<string>(); // not needed 
+0

谢谢,我可能会使用这个解决方案。但我认为这是一个错误,因为所有类型的行为都应该是相同的,而如果我使用'List'或'array',我会得到不同的结果。 –

+0

对我而言,这是不正确的。如果您将'new string [0]'设置为'IList'字段,则您将获得相同的行为。正如我所指出的,默认的反序列化行为是为Enumerable和IList接口字段创建一个List实例。如果你指定一个明确的对象类型,它将使用它,但有很多方法来实例化一个'IEnumerable'。如果违背默认值,唯一的方法就是添加'$ type'元数据 –

1

这是不是一个错误,但是这是正常现象。您正在全球设置TypeNameHandling。而不是全局设置类型的名义处理您可以用属性像下面标记属性,以避免它们被包含设置TypeNameHandling.Auto

[JsonProperty(TypeNameHandling = TypeNameHandling.None)] 

这里有一个例子:

public class MyClass 
    { 
     // Indicate the property not to apply any type handling 
     [JsonProperty(TypeNameHandling=TypeNameHandling.None)] 
     public IList<string> Values { get; set; } 

     public string Name { get; set; } 
    } 

这会给你不想要的结果受到全球声明的任何TypeNameHandling设置的影响。

+0

通常我不喜欢在我的代码中插入序列化属性,但最终这可能是一个好的解决方案但我不明白为什么其他类型的行为是不同的。例如,如果我宣布该物业为IList 并将其设置为列表。我认为这是一个bug ... –

+0

这是支持派生类型的正确反序列化的行为。当你声明它是全局的时候,它适用于所有的属性。这就是为什么TypeNameHandling的支持是作为属性提供的。它也可以以其他方式完成,例如将需要特殊TypeHandling的属性标记为Auto并且根本不使用全局设置。 – vendettamit

+0

是的,我明白,但为什么IList有不同的行为?文件似乎证实了我的期望。 –