<Customer>
<FirstName>SomeValue</FirstName>
<LastName>Somevalue</LastName>
<Address/>
</Customer>
我有上面的xml,Address元素是一个复杂的对象。当我尝试反序列化为C#对象时,地址对象中的所有属性都设置为null,但我的要求是将其自身的地址对象设置为null。有没有办法实现这个目标?
答案 0 :(得分:2)
要确认您的问题,您要问:在反序列化XML时,我是否可以将空元素映射到null
属性值,但是将非空元素映射到非{{1}属性值?
假设您使用的是XmlSerializer
,则不会开箱即用。当属性{http://www.w3.org/2001/XMLSchema}nil
(通常缩写为null
)具有值XmlSerializer
时,null
只会将元素映射到xsi:nil
值。来自Xsi:nil Attribute Binding Support:
XmlSerializer类将 nil 属性的真值等同于空引用,执行以下运行时转换:
- 将XML文档反序列化为对象时:如果XmlSerializer类遇到指定xsi:nil =&#34; true&#34;的XML元素,则会将null引用(如果适用)分配给相应的对象。
- 将对象序列化为XML文档时:如果XmlSerializer类遇到对应于XML元素的对象的空引用,则它会生成一个指定xsi的元素:nil =&#34; true&#34;或者完全离开元素,取决于nillable =&#34; true&#34;设置适用。
由于您的空"true"
元素中不存在xsi:nil
,因此它不会自动映射到<Address>
。
作为一种解决方法,您可以引入额外的&#34;代理&#34;将null
转换为Address
的属性,在反序列化期间,检查所设置的Customer
是否具有默认值,如果是,则将基础地址值设置为Address
。例如,如果您的类看起来像:
null
你可以通过以下几种方式做到这一点:
反思。介绍以下扩展方法:
public class Address
{
public string Street1 { get; set; }
public string Street2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
public string Country { get; set; }
}
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Address Address { get; set; }
}
然后按如下方式修改public static class ObjectExtensions
{
public static IEnumerable<object> Members(this object obj)
{
if (obj == null)
return new object[0];
var type = obj.GetType();
return type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.GetIndexParameters().Length == 0 && p.GetGetMethod(true) != null && p.CanRead)
.Select(p => p.GetValue(obj, new object[0]))
.Concat(type.GetFields().Select(f => f.GetValue(obj)));
}
public static bool IsDefault(this object obj)
{
if (obj == null)
return true;
var type = obj.GetType();
if (type.IsValueType)
{
return obj.Equals(Activator.CreateInstance(type, true));
}
return false;
}
public static bool MembersAreDefault(this object obj)
{
return obj.Members().All(v => v.IsDefault());
}
}
:
Customer
属性public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
[XmlIgnore]
public Address Address { get; set; }
[XmlElement("Address")]
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DebuggerBrowsable(DebuggerBrowsableState.Never)]
public Address SerializableAddress
{
get
{
return Address;
}
set
{
if (value != null && value.MembersAreDefault())
value = null;
Address = value;
}
}
}
使用反射检查传入的SerializableAddress
是否具有任何非默认值。如果不是,则将基础属性设置为null。
此解决方案功能强大且可重复使用,但由于它使用反射,性能可能不会很好。
使用标准接口检查是否已在给定类型中设置了任何属性。首先,介绍以下内容:
Address
接下来,为public interface IHasDefaultMemberValues
{
bool MembersAreDefault();
}
实现该接口:
Address
最后,将public class Address : IHasDefaultMemberValues
{
// Properties as above.
#region IHasDefaultMemberValues Members
public virtual bool MembersAreDefault()
{
return Street1 == null && Street2 == null && City == null && State == null && Zip == null && Country == null;
}
#endregion
}
修改为与解决方案#1完全相同。
此解决方案具有高性能,但在将新属性添加到Customer
时依赖于MembersAreDefault()
正确维护。
答案 1 :(得分:-1)
您可以使用 XmlIgnore 属性排除对象的属性
[XmlIgnore]
public Address {get; set;}