在序列化期间排除某些属性而不更改原始类

Sch*_*ini 12 c# xml-serialization

我正在尝试序列化具有多个属性的对象,但我不想在序列化中包含所有属性.另外,我想更改日期格式.

当然我可以添加[XmlIgnore],但我不允许更改原始类.

我能想到的唯一选择是创建一个新类并复制两个类之间的所有内容.但这将是丑陋的,需要大量的手动代码.

是否有可能创建一个子类,因为原始不是抽象的?

我的问题是:

  1. 如何在不更改原始类的情况下排除某些属性?

  2. 如何自定义输出XML的日期格式?

要求:

  1. 尽可能强大的打字

  2. 序列化的XML应该是可反序列化的

提前致谢.

Sch*_*ini 11

对于谁有兴趣,我决定使用XmlAttributeOverrides,但使它们更强大的类型(我讨厌键入属性名称作为字符串).这是我用过的扩展方法:

    public static void Add<T>(this XmlAttributeOverrides overrides, Expression<Func<T, dynamic>> propertySelector, XmlAttributes attributes)
    {
        overrides.Add(typeof(T), propertySelector.BuildString(), attributes);
    }

    public static string BuildString(this Expression propertySelector)
    {
        switch (propertySelector.NodeType)
        {
            case ExpressionType.Lambda:
                LambdaExpression lambdaExpression = (LambdaExpression)propertySelector;
                return BuildString(lambdaExpression.Body);

            case ExpressionType.Convert:
            case ExpressionType.Quote:
                UnaryExpression unaryExpression = (UnaryExpression)propertySelector;
                return BuildString(unaryExpression.Operand);

            case ExpressionType.MemberAccess:

                MemberExpression memberExpression = (MemberExpression)propertySelector;
                MemberInfo propertyInfo = memberExpression.Member;

                if (memberExpression.Expression is ParameterExpression)
                {
                    return propertyInfo.Name;
                }
                else
                {
                    // we've got a nested property (e.g. MyType.SomeProperty.SomeNestedProperty)
                    return BuildString(memberExpression.Expression) + "." + propertyInfo.Name;
                }

            default:
                // drop out and throw
                break;
        }
        throw new InvalidOperationException("Expression must be a member expression: " + propertySelector.ToString());
    }
Run Code Online (Sandbox Code Playgroud)

然后,为了忽略属性,我可以将它精美地添加到忽略列表中:

    var overrides = new XmlAttributeOverrides();
    var ignore = new XmlAttributes { XmlIgnore = true };
    overrides.Add<MyClass>(m => m.Id, ignore);
    overrides.Add<MyClass>(m => m.DateChanged, ignore);
    Type t = typeof(List<MyClass>);
    XmlSerializer serial = new XmlSerializer(t, overrides);
Run Code Online (Sandbox Code Playgroud)

  • 使用`XmlAttributeOverrides`构造的任何`XmlSerializer`只能构造一次,然后缓存以供以后重用.有关说明,请参阅[使用StreamReader和XmlSerializer进行内存泄漏](/sf/ask/1672800181/)和[XmlSerializer extraTypes内存泄漏](/sf/ask/2722464671/). (3认同)

Rob*_*ine 9

您可以通过利用XmlSerializer不将nulls序列化到输出的事实来排除某些属性.因此,对于引用类型,您可以忽略那些不希望出现在xml中的属性.

生成的xml可以反序列化回同一个类,但省略的字段显然是null.

但是,这对您更改日期格式的愿望没有帮助.为此,您需要创建一个新类,其日期为您想要的格式的字符串,或者您可以实现IXmlSerializable,让您完全控制xml.[值得注意的是,日期数据类型在XML中具有标准格式,因此通过更改它将不再是XML日期 - 您可能不关心].

[ 编辑回复您的意见]

还有一个额外的技巧可以用来"消失"null null null类型,但它确实需要更改你的类.序列化程序在序列化时MyProperty还会检查是否存在调用的属性MyProperySpecified.如果它存在并返回false,则不会序列化item属性:

public class Person
{
    [XmlElement]
    public string Name { get; set; }

    [XmlElement]
    public DateTime? BirthDate { get; set; }

    public bool BirthDateSpecified
    {
        get { return BirthDate.HasValue; }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您准备添加此属性,则可以在null时删除可空类型.事实上 - 现在我考虑一下 - 根据您的使用场景,这可能是一种删除其他属性的有用方法.

  • 看我的编辑 - 另一种方法可以解决你的问题. (2认同)