Как читать с интерфейсами в модели? - PullRequest
0 голосов
/ 19 июня 2020

Я хотел бы знать, как читать JSON с макетом c Dynami в моем объекте, имеющем интерфейс IPeople. При попытке получить сообщение об ошибке:

«Не удалось создать экземпляр типа« xxxx ». Тип - это интерфейс или абстрактный класс, и его нельзя создать.

Я потратил 2 дня на поиск в Google и попытался использовать конвертеры, и он работает только для одного объекта за раз, поэтому мне пришлось бы выбрать между преобразователем персонала и преобразователем зрителя.

Как я могу получить оба объекта для загрузки с помощью интерфейса IPeople, который загружается в объект Staff, если обнаружены данные персонала, и объект Spectator, если обнаружены данные наблюдателя (возможно, больше типов объектов имеют уникальные свойства).

{
    "appCore": 
    {
        "Crowd": 
        [
            {
                "Name": "Name1",
                "Staff":
                {  
                    "PopupText":
                    [
                        {   "DisplayName":"No Popup Text","PopupValue":"", "IsSeperator":false},
                        {   "DisplayName":"--------------","PopupValue":"", "IsSeperator":true},
                        {   "DisplayName":"HT","PopupValue":"HT", "IsSeperator":false}
                    ]

                },
                "Spectator":
                {  
                    "PopupText2":
                    [
                        {   "DisplayName":"No Popup Text","PopupValue":"", "Cheese":"hiih"},
                        {   "DisplayName":"--------------","PopupValue":"",  "Cheese":"hiih"},
                        {   "DisplayName":"Half-Time","PopupValue":"Half-Time",  "Cheese":"hiih"}
                    ]
                }          
            }
        ]
    }
}

C# Модели:

public class Crowd : ICrowd
{
    public IPeople People { get; set; }
}


public class Staff :  IPeople
{
    IList<PopupTextData> PopupText { get; set; }
}

public class Spectator : IPeople
{
    IList<PopupTextData2> PopupText2 { get; set; }
}

public class PopupTextData
{
    public string DisplayName { get; set; }
    public string PopupValue { get; set; }
    public bool IsSeperator { get; set; }
}

public class PopupTextData2
{
    public string DisplayName { get; set; }
    public string PopupValue { get; set; }
    public string Cheese { get; set; }
}

Код, используемый для чтения данных:

settings.ForEach(type =>
{
    builder.Register(c => c.Resolve<MCoreReader>().LoadSection(type))
        .As(type.GetInterfaces())
        .AsImplementedInterfaces()
        .InstancePerRequest()
        .InstancePerLifetimeScope();
});

public static object LoadSection(Type type, string _configurationFilePath, string _sectionNameSuffix)
{
    if (!File.Exists(_configurationFilePath))
        return Activator.CreateInstance(type);

    var jsonFile = File.ReadAllText(_configurationFilePath);
    var section = ToCamelCase(type.Name.Replace(_sectionNameSuffix, string.Empty));
    var settingsData = JsonConvert.DeserializeObject<dynamic>(jsonFile, JsonSerializerSettings);
    var settingsSection = settingsData[section];
    return settingsSection == null
        ? Activator.CreateInstance(type)
        : JsonConvert.DeserializeObject(JsonConvert.SerializeObject(settingsSection), type, JsonSerializerSettings);
}

private class SettingsReaderContractResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        var props = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
            .Select(p => CreateProperty(p, memberSerialization))
            .Union(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                .Select(f => CreateProperty(f, memberSerialization)))
            .ToList();
        props.ForEach(p =>
        {
            p.Writable = true;
            p.Readable = true;
        });

        return props;
    }
}

private static readonly JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Auto,
    ContractResolver = new SettingsReaderContractResolver(),
};

1 Ответ

0 голосов
/ 19 июня 2020

Предполагая, что вы управляете Json, вот рабочий пример: я немного изменил структуру классов.

Он использует TypeNameHandling.All , который записывает информацию о типе в Json - как $type -, поэтому при десериализации (с использованием тех же настроек) он может восстановить тип.

void Main() {
    var crowd = new Crowd {
        People = new List<IPeople> {
            new Staff {
                PopupText = new List<PopupTextData> {
                new PopupTextData { DisplayName = "Staff"}
            }},
            new Spectator {
                PopupText = new List<PopupTextData> {
                new PopupTextData { DisplayName = "Spectator"}
            }},
        }
    };

    var settings = new JsonSerializerSettings {
        TypeNameHandling = TypeNameHandling.All,
        TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple
    };

    var json = JsonConvert.SerializeObject(crowd, settings);

    var newCrowd = JsonConvert.DeserializeObject<ICrowd>(json, settings);
    Console.WriteLine(newCrowd.People.Count); // outputs '2'


}

public interface ICrowd {
    IList<IPeople> People { get; set; }
}

public interface IPeople {
    IList<PopupTextData> PopupText { get; set; }
}

public class Crowd : ICrowd {
    public IList<IPeople> People { get; set; }
}

public class Staff : IPeople {
    public IList<PopupTextData> PopupText { get; set; }
}

public class Spectator : IPeople {
    public IList<PopupTextData> PopupText { get; set; }
}

public class PopupTextData {
    public string DisplayName { get; set; }
    public string PopupValue { get; set; }
    public bool IsSeperator { get; set; }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...