Десериализовать список строк JSON, чтобы найти правильную модель - PullRequest
3 голосов
/ 16 октября 2019

Это довольно раздражает, и мне нужно только запустить этот код ОДИН РАЗ. После этого все будут удалены (это код миграции)

У меня есть List<string> строк JSON. Они содержат различные форматы объектов JSON, которые могут выглядеть следующим образом:

{
    "id": 123
}
{
    "id": "7521b497-abb7-46b8-bddc-177a6fd9f974",
    "folderId": 123
}
{
    "folderId": 123
}

и так далее. Мне нужно получить 123, который может быть в свойствах id и folderId. Если я просто сделаю:

class IdModel {
    public int Id { get; set; }
}

//inside a function
var model = JsonConvert.DeserializeObject<IdModel>(json);

, то произойдет сбой при переходе ко второму JSON, потому что id - это GUID. Вместо этого нужно искать FolderId, что означает, что я могу сделать что-то вроде этого:

class IdModel {
    public int Id { get; set; }
}

class FolderIdModel {
    public int FolderId { get; set; }
}

//inside a function
int folderId;

try {
    var model = JsonConvert.DeserializeObject<FolderIdModel>(json);
    folderId = model.FolderId;
} catch {
    var model = JsonConvert.DeserializeObject<IdModel>(json);
    folderId = model.Id;
}

Это было бы "хорошо" для этого сценария, но у меня, вероятно, есть 10 различных объектов JSON, чтовсе выглядят по-другому. FolderId > Id, потому что я всегда знаю, что FolderId правильный, если только у него нет FolderId, в этом случае он МОЖЕТ иметь Id (должен взорваться, если ни FolderId, ни Id не верны).

Мой вопрос:Есть ли умный способ десериализации для разных моделей, не глядя на JSON? Помните, что Id может быть как GUID, так и целым числом, в зависимости от объектов JSON.

Я знаю, что это действительно плохо, и мне жаль.

Ответы [ 4 ]

2 голосов
/ 16 октября 2019

Я бы добавил дополнительное свойство к модели, которое получает реальный идентификатор (FolderId или Id, в зависимости от того, который установлен правильно). Модель будет выглядеть следующим образом:

class Model
        {
            public string Id { get; set; }
            public int? FolderId { get; set; }
            public int RealFolderId
            {
                get
                {
                    if (FolderId != null)
                    {
                        return FolderId.Value;
                    }
                    int id;
                    if (int.TryParse(Id, out id))
                    {
                        return id;
                    }
                    throw new Exception("This explodes");
                }
            }
        }

Идентификатор сериализуется в виде строки, поэтому он не будет разрываться, когда Id равен Guid или когда он равен int. Exception выбрасывается, когда оба, FolderId и Id имеют «неправильные значения»;Ни один из них не является int.

Остальной код будет довольно простым:

var deserialized = JsonConvert.DeserializeObject<Model>(json);
int folderId = deserialized.RealFolderId;
2 голосов
/ 16 октября 2019

Да, вы можете использовать тип dynamic, где он будет соответствовать результату вашего объекта Json, а затем проверить, является ли тип значения Guid или int следующим образом:

int folderId;
var model = JsonConvert.DeserializeObject<dynamic>(json);
folderId = model.id != null && model.id is int ? model.id : model.folderId;

Если есть больше возможных результатов, вы можете сломать этот троичный оператор и проверить их единственное число.

2 голосов
/ 16 октября 2019

Я бы просто десериализовал оба с одним и тем же классом, а затем проанализировал их в соответствии со значениями свойств. Например:

public class IdModel
{
    public string Id { get; set; }
    public string FolderId { get; set; }

    public int Value
    {
        get
        {
            if (int.TryParse(Id, out int value))
            {
                return value;
            }
            else if (int.TryParse(FolderId, out value))
            {
                return value;
            }
            else
            {
                throw new Exception("This model has no valid id");
            }
        }
    }
}

Использование:

string json1 = "{\"id\": 123}";
string json2 = "{\"id\": \"7521b497-abb7-46b8-bddc-177a6fd9f974\",\"folderId\": 123}";
string json3 = "{\"folderId\": 123}";

IdModel model1 = JsonConvert.DeserializeObject<IdModel>(json1); // model1.Value = 123
IdModel model2 = JsonConvert.DeserializeObject<IdModel>(json2); // model2.Value = 123
IdModel model3 = JsonConvert.DeserializeObject<IdModel>(json3); // model3.Value = 123
1 голос
/ 16 октября 2019

Вы можете попробовать использовать DeserializeAnonymousType метод, что-то вроде этого

var responseObject = JsonConvert.DeserializeAnonymousType(json, new { id = "" });

, который преобразует его в требуемый тип (int или Guid) или использует просто object тип

...