Update
Вопрос 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.
@ Łukasz - ОК, я пошел вперед и сообщил о проблеме, [Deserializing unclosed object успешно, когда объект имеет параметризованный конструктор. # Одна тысяча тридцать восемь] (https://github.com/JamesNK/Newtonsoft.Json/issues/1038). – dbc
О, я был в процессе, но тогда я остановлюсь. Спасибо за помощь –