Полиморфная десериализуйте JSON с использованием DI Container для создания экземпляровC#

Место общения программистов C#
Ответить
Anonymous
 Полиморфная десериализуйте JSON с использованием DI Container для создания экземпляров

Сообщение Anonymous »

Рассмотрим эти классы модели: < /p>

Код: Выделить всё

[JsonPolymorphic(TypeDiscriminatorPropertyName = "$type")]
[JsonDerivedType(typeof(A), typeDiscriminator: nameof(A))]
[JsonDerivedType(typeof(B), typeDiscriminator: nameof(B))]
interface IMyType
{
}

class A(DependencyA dependency) : IMyType
{
public int X { get; set; } = dependency.GetValue();
}

class B(DependencyB dependency) : IMyType
{
public int Y { get; set; } = dependency.GetValue();
}

class DependencyA
{
public int GetValue() => 42;
}

class DependencyB
{
public int GetValue() => 123;
}
di -контейнер используется microsoft.dependencyInction .
Пример:

Код: Выделить всё

static void Main(string[] args)
{
IServiceCollection services = new ServiceCollection()
.AddTransient()
.AddTransient()
.AddTransient()
.AddTransient();

IServiceProvider provider = services.BuildServiceProvider();

IMyType[] items =
[
provider.GetRequiredService(),
provider.GetRequiredService()
];

Print(items);

string json = JsonSerializer.Serialize(items);
Console.WriteLine(json);

// This line is invalid but states my intension:
IMyType[]? deserialized = JsonSerializer.Deserialize(json);
// ^^^^^^^^
// System.InvalidOperationException: 'Each parameter in the deserialization constructor
// on type 'ConsoleAppExample.A' must bind to an object property or field on
// deserialization. Each parameter name must match with a property or field on the object.
// Fields are only considered when 'JsonSerializerOptions.IncludeFields' is enabled.
// The match can be case-insensitive.'

Print(deserialized);
}

static void Print(IMyType[]? items)
{
foreach (IMyType instance in items ?? [])
{
switch (instance)
{
case A aInstance:
Console.WriteLine($"A.X = {aInstance.X}");
break;

case B bInstance:
Console.WriteLine($"B.Y = {bInstance.Y}");
break;
}
}
}
< /code>
Начало вывода (до исключения): < /p>
A.X = 42
B.Y = 123
[{"$type":"A","X":42},{"$type":"B","Y":123}]
Сериализованный выход JSON, как и ожидалось. Поместите, чтобы ввести iserviceprovider экземпляр, где он может получить полученный тип и вернуть объект для Deserializer.
ОК, вот моя попытка:

Код: Выделить всё

class PolymorphicTypeResolver(IServiceProvider serviceProvider) : DefaultJsonTypeInfoResolver
{
static Type[] RegisteredTypes = [typeof(A), typeof(B)];

public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
{
var jsonTypeInfo = base.GetTypeInfo(type, options);

if (jsonTypeInfo.Type == typeof(IMyType))
{
// WRONG LINE because here `type` is always `IMyType`
// But where can I get the derived one?
jsonTypeInfo.CreateObject = () => serviceProvider.GetRequiredService(type);

jsonTypeInfo.PolymorphismOptions = new JsonPolymorphismOptions
{
TypeDiscriminatorPropertyName = "$type",
UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FailSerialization,
};

foreach (var derived in RegisteredTypes)
{
jsonTypeInfo.PolymorphismOptions.DerivedTypes.Add(new JsonDerivedType(derived, derived.Name));
}
}

return jsonTypeInfo;
}
}
предпочтительнее, что решение для собственного удобного.

Подробнее здесь: https://stackoverflow.com/questions/797 ... -instances
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»