Я пытаюсь создать JsonConverter
, который работает следующим образом:
- Применяется только к
abstract
class
es и interface
s - Записывает вJSON "по умолчанию"
- Читает из JSON, просматривая все производные конкретные классы и пытаясь десериализовать каждый из них.Использует первый, который работает, или, если работает несколько, сгенерирует ошибку (с возможностью переопределить этот параметр и вместо этого взять первый, который работает).
- Он не работает рекурсивно, означая, что любойСвойства классов, которые являются абстрактными или интерфейсными, должны быть помечены атрибутом
Пример того, как это должно работать:
Если у нас есть
/// <summary>
/// Interface with multiple non-conflicting implementations
/// </summary>
[JsonConverter(typeof(PolyJsonConverter))]
private interface IBar
{
string StringProperty { get; }
}
private class Bar1 : IBar
{
public string StringProperty { get; set; }
public string OtherStringProperty { get; set; }
}
private class Bar2 : IBar
{
public string StringProperty { get; set; }
public double[] DoubleArrayProperty { get; set; }
}
, тогда здесьэто тест, который должен пройти
[TestMethod]
public void InterfaceWithNonConflictingImplementationsDerivedFromOtherInterfaceCanSerializeAndDeserializeToBaseInterfaceTest()
{
var concreteBaz = new Baz1()
{
StringProperty = "blah blah",
IntArrayProperty = new int[] { 1, 2, 3 }
};
string json = JsonConvert.SerializeObject(concreteBaz);
IBar bar = JsonConvert.DeserializeObject<IBar>(json);
Assert.IsNotNull(bar);
Assert.AreEqual(concreteBaz.StringProperty, bar.StringProperty);
}
У меня есть попытка, которая почти работает, за исключением того, что в ReadJson
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jObject = JObject.Load(reader);
string json = jObject.ToString();
var derivedTypes = GetDerivedTypes(objectType);
object match = null;
foreach (var dervivedType in derivedTypes)
{
object deserialized;
try
{
deserialized = JsonConvert.DeserializeObject(json, dervivedType, requiredSerializerSettings);
}
catch
{
continue;
}
if (match != null)
{
if (conflictResolutionMode == ConflictResolutionMode.ThrowError)
{
throw new JsonException($"Multiple matching implementations found for base type {objectType}.");
}
}
else
{
match = deserialized;
if (conflictResolutionMode == ConflictResolutionMode.UseArbitrary)
{
break;
}
}
}
if (match == null)
{
throw new JsonException($"Could not find match for type {objectType} among derived types {string.Join(", ", derivedTypes)}.");
}
return match;
}
private static IEnumerable<Type> GetDerivedTypes(Type baseType)
{
return derivedTypesCache.GetOrAdd(baseType, t => QueryDerivedTypes(t));
}
private static IEnumerable<Type> QueryDerivedTypes(Type baseType)
{
return from domainAssembly in AppDomain.CurrentDomain.GetAssemblies()
from assemblyType in domainAssembly.GetTypes()
where baseType.IsAssignableFrom(assemblyType)
&& !assemblyType.IsInterface
&& !assemblyType.IsAbstract
select assemblyType;
}
я понимаю, почему "я"но я не могу понять, как это решить.Есть идеи?