!=-运算符对结构失败
!=-operator fails for struct
我有一些 classes 有一些 XmlSerializer
的序列化属性,例如XmlElement
或 XmlArray
。现在我也想将这些现有属性用于 Json-序列化。
因此我创建了一个 class 派生自 NewtonSoft 的 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();
}
}
现在我有一个测试-class来测试上面的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))
得到满足,这就是我在 property.PropertyName = item.Value.MemberName;
处得到 NullReferenceException
的原因。
当我在 attribute.NamedArguments
上添加监视(这是一个 List<CustomAttributeNamedArgument>
,因此是一个值类型列表)时,该列表中的元素为零,因此 FirstOrDefault
应该 return 该结构的默认值是什么。但是 !=
-运算符 returns true
.
那是因为 CustomAttributeNamedArgument
结构像这样覆盖了它的相等运算符:
public static bool operator ==(CustomAttributeNamedArgument left, CustomAttributeNamedArgument right)
{
return left.Equals((object) right);
}
public override bool Equals(object obj)
{
return obj == (ValueType)this;
}
所以基本上使用引用相等语义,即使它是一个结构。我不清楚为什么会这样,但这就是您检查失败的原因。即使这样:
default(CustomAttributeNamedArgument) == default(CustomAttributeNamedArgument);
Returns false 这种语义。
要修复你可以使用像
这样的东西
var item = attribute.NamedArguments?.Where(x => x.MemberName == "ElementName")
.Cast<CustomAttributeNamedArgument?>().FirstOrDefault();
if (item.HasValue) {
property.PropertyName = item.Value.MemberName;
return;
}
或类似于 return null 作为默认值的方式。
我有一些 classes 有一些 XmlSerializer
的序列化属性,例如XmlElement
或 XmlArray
。现在我也想将这些现有属性用于 Json-序列化。
因此我创建了一个 class 派生自 NewtonSoft 的 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();
}
}
现在我有一个测试-class来测试上面的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))
得到满足,这就是我在 property.PropertyName = item.Value.MemberName;
处得到 NullReferenceException
的原因。
当我在 attribute.NamedArguments
上添加监视(这是一个 List<CustomAttributeNamedArgument>
,因此是一个值类型列表)时,该列表中的元素为零,因此 FirstOrDefault
应该 return 该结构的默认值是什么。但是 !=
-运算符 returns true
.
那是因为 CustomAttributeNamedArgument
结构像这样覆盖了它的相等运算符:
public static bool operator ==(CustomAttributeNamedArgument left, CustomAttributeNamedArgument right)
{
return left.Equals((object) right);
}
public override bool Equals(object obj)
{
return obj == (ValueType)this;
}
所以基本上使用引用相等语义,即使它是一个结构。我不清楚为什么会这样,但这就是您检查失败的原因。即使这样:
default(CustomAttributeNamedArgument) == default(CustomAttributeNamedArgument);
Returns false 这种语义。
要修复你可以使用像
这样的东西var item = attribute.NamedArguments?.Where(x => x.MemberName == "ElementName")
.Cast<CustomAttributeNamedArgument?>().FirstOrDefault();
if (item.HasValue) {
property.PropertyName = item.Value.MemberName;
return;
}
或类似于 return null 作为默认值的方式。