我遇到了一个奇怪的问题:如果这样的字符串{"text":"s","cursorPosition":189,"dataSource":"json_northwind",
不是正确的json,它仍然会被成功解析。
这是班级:
public class CompletionDataRequest
{
public CompletionDataRequest(string text, int cursorPosition, string dataSource, string project)
{
Text = text;
CursorPosition = cursorPosition;
DataSource = dataSource;
Project = project;
}
public string Text { get; }
public int CursorPosition { get; }
public string DataSource { get; }
public string Project { get; }
}
这是令人惊讶的成功的测试:
var s = @"{""text"":""s"",""cursorPosition"":189,""dataSource"":""json_northwind"",";
var request = JsonConvert.DeserializeObject<CompletionDataRequest>(s);
request.Text.Should().Be("s");
request.CursorPosition.Should().Be(189);
request.DataSource.Should().Be("json_northwind");
request.Project.Should().BeNull();
库是否有一些松散的解析规则,或者这可能是一个错误?我是图书馆版本9.0.1
答案 0 :(得分:5)
<强>更新强>
此问题已打开问题Deserializing unclosed object succeeds when the object has a parameterized constructor. #1038。它已在变更集Json.NET release 10.0.1中的0721bd4中修复。
原始答案
您在Json.NET中发现了一个错误。只有在使用参数化构造函数构造对象时才会出现它。如果我修改您的对象以具有非参数化构造函数:
public class CompletionDataRequest
{
public CompletionDataRequest(string text, int cursorPosition, string dataSource, string project)
{
Text = text;
CursorPosition = cursorPosition;
DataSource = dataSource;
Project = project;
}
[JsonConstructor]
private CompletionDataRequest()
{
}
[JsonProperty]
public string Text { get; private set; }
[JsonProperty]
public int CursorPosition { get; private set; }
[JsonProperty]
public string DataSource { get; private set; }
[JsonProperty]
public string Project { get; private set; }
}
然后Json.NET将正确抛出JsonSerializationException
。
错误的原因如下。使用无参数构造函数创建对象时,Json.NET首先构造对象,然后使用JsonSerializerInternalReader.PopulateObject()
填充它。此方法具有以下(简化)逻辑:
private object PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, string id)
{
bool finished = false;
do
{
switch (reader.TokenType)
{
case JsonToken.PropertyName:
{
// Read and process the property.
}
case JsonToken.EndObject:
finished = true;
break;
case JsonToken.Comment:
// ignore
break;
default:
throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
}
} while (!finished && reader.Read());
if (!finished)
{
ThrowUnexpectedEndException(reader, contract, newObject, "Unexpected end when deserializing object.");
}
return newObject;
}
如您所见,有逻辑if (!finished)
来验证对象实际上是否已关闭。
但是,在使用参数化构造函数创建对象时,使用JsonSerializerInternalReader.ResolvePropertyAndCreatorValues()
在构造对象之前读取属性:
private List<CreatorPropertyContext> ResolvePropertyAndCreatorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType)
{
List<CreatorPropertyContext> propertyValues = new List<CreatorPropertyContext>();
bool exit = false;
do
{
switch (reader.TokenType)
{
case JsonToken.PropertyName:
// Read and process the property.
break;
case JsonToken.Comment:
break;
case JsonToken.EndObject:
exit = true;
break;
default:
throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
}
} while (!exit && reader.Read());
return propertyValues;
}
正如您所看到的那样,exit
没有等效检查。
为此打开了一个问题Deserializing unclosed object succeeds when the object has a parameterized constructor. #1038。