У меня есть несколько классов, которые имеют некоторые атрибуты сериализации для XmlSerializer
, например XmlElement
или XmlArray
. Теперь я хочу использовать эти существующие атрибуты и для Json-сериализации.
Для этого я создал класс, производный от NewtonSoft´s DefaultContractResolver
:
public class XmlToJsonContractResolver : DefaultContractResolver
{
internal void ConfigureProperty(MemberInfo member, JsonProperty property)
{
ConfigureNamedMembers(member, property);
}
private static void ConfigureNamedMembers(MemberInfo member, JsonProperty property)
{
foreach (var attribute in member.GetCustomAttributesData().Where(x => x.AttributeType.Namespace == typeof(XmlElementAttribute).Namespace))
{
// the elementName may either be stored in the named argument "ElementName" or was provided to the
// constructor of the appropriate Xml-attribute
var item = attribute.NamedArguments?.FirstOrDefault(x => x.MemberName == "ElementName");
if (item.HasValue && item.Value != default(CustomAttributeNamedArgument))
{
property.PropertyName = item.Value.MemberName;
return;
}
// ElementName is provided to constructor of xml-attribute
throw new NotImplementedException();
}
}
Теперь у меня есть тестовый класс для тестирования ConfigureProperty
-метода сверху:
private class A
{
[XmlElement("AnIntAlias")]
public int AnXmlSerializableInt { get; set; }
}
Как видите, XmlElementAttribute
не имеет именованных аргументов. Вместо этого ElementName
-proerty устанавливается через его конструктор, поэтому код выше сначала проверяет наличие именованных аргументов.
Это код, который использует A
:
var target = new XmlToJsonContractResolver();
var jsonProperty = new JsonProperty { PropertyName = memberName };
var member = typeof(A).GetMember(nameof(A.AnXmlSerializableInt)).First();
target.ConfigureProperty(member, jsonProperty);
var result = jsonProperty.PropertyName;
Когда я отлаживаю этот код, я выполняю первое условие if (item.HasValue && item.Value != default(CustomAttributeNamedArgument))
, поэтому я получаю NullReferenceException
при property.PropertyName = item.Value.MemberName;
.
Когда я добавляю часы на attribute.NamedArguments
(который является List<CustomAttributeNamedArgument>
и, следовательно, списком типов значений), в этом списке есть ноль элементов, поэтому FirstOrDefault
должно возвращать любое значение по умолчанию для этого структура. Однако !=
-оператор возвращает true
.