删除C#

问题描述

我正在将对象序列化为XML,该XML在某些属性上具有DefaultValue属性。在某些情况下,我想在序列化期间禁用所有这些认值。是否可以在运行时删除属性

[Serializable]
[XmlType(TypeName = "MyType")]
public class MyType
{
    public MyType()
    {
        MyValue = false;
    }

    [XmlElement(ElementName = "myValue",Form = XmlSchemaForm.Unqualified)]
    [DefaultValue(false)]
    public bool MyValue { get; set; }
}


public class TestSerializer
{
    public void Serialize()
    {
        XmlSerializer serializer = new XmlSerializer(typeof(MyType));

        using (TextWriter writer = new StreamWriter(stream,Encoding.UTF8,1024,true))
        {
            serializer.Serialize(writer,new MyType());
        }
    }
}

我已经开始考虑使用反射来完成此操作,但是无法使其正常工作。 XmlAttributeOverrides似乎也无济于事,但也许我只是还没有找到正确的方法。有什么想法吗?

解决方法

XmlSerializerIgnoringDefaultValuesKey.Createthis answer Force XML serialization of XmlDefaultValue values 基本上可以满足您的需求,但是您通过应用{覆盖了MyValue的XML元素名称{1}},据说在该答案中未实现:

使用此XmlAttributes对象覆盖时,需要保留的所有属性都需要转移到该新对象中。

以下增强版本支持传输[XmlElement][XmlArray][XmlArrayItem]覆盖属性:

[XmlElement(ElementName = "myValue",Form = XmlSchemaForm.Unqualified)]

并像这样使用它:

public abstract class XmlSerializerKey
{
    static class XmlSerializerHashTable
    {
        static Dictionary<object,XmlSerializer> dict;

        static XmlSerializerHashTable()
        {
            dict = new Dictionary<object,XmlSerializer>();
        }

        public static XmlSerializer GetSerializer(XmlSerializerKey key)
        {
            lock (dict)
            {
                XmlSerializer value;
                if (!dict.TryGetValue(key,out value))
                    dict[key] = value = key.CreateSerializer();
                return value;
            }
        }
    }

    readonly Type serializedType;

    protected XmlSerializerKey(Type serializedType)
    {
        this.serializedType = serializedType;
    }

    public Type SerializedType { get { return serializedType; } }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(this,obj))
            return true;
        else if (ReferenceEquals(null,obj))
            return false;
        if (GetType() != obj.GetType())
            return false;
        XmlSerializerKey other = (XmlSerializerKey)obj;
        if (other.serializedType != serializedType)
            return false;
        return true;
    }

    public override int GetHashCode()
    {
        int code = 0;
        if (serializedType != null)
            code ^= serializedType.GetHashCode();
        return code;
    }

    public override string ToString()
    {
        return string.Format(base.ToString() + ": for type: " + serializedType.ToString());
    }

    public XmlSerializer GetSerializer()
    {
        return XmlSerializerHashTable.GetSerializer(this);
    }

    protected abstract XmlSerializer CreateSerializer();
}

public abstract class XmlSerializerWithExtraTypesKey : XmlSerializerKey
{
    static IEqualityComparer<HashSet<Type>> comparer;

    readonly HashSet<Type> extraTypes = new HashSet<Type>();

    static XmlSerializerWithExtraTypesKey()
    {
        comparer = HashSet<Type>.CreateSetComparer();
    }

    protected XmlSerializerWithExtraTypesKey(Type serializedType,IEnumerable<Type> extraTypes)
        : base(serializedType)
    {
        if (extraTypes != null)
            foreach (var type in extraTypes)
                this.extraTypes.Add(type);
    }

    public Type[] ExtraTypes { get { return extraTypes.ToArray(); } }

    public override bool Equals(object obj)
    {
        if (!base.Equals(obj))
            return false;
        XmlSerializerWithExtraTypesKey other = (XmlSerializerWithExtraTypesKey)obj;
        return comparer.Equals(this.extraTypes,other.extraTypes);
    }

    public override int GetHashCode()
    {
        int code = base.GetHashCode();
        if (extraTypes != null)
            code ^= comparer.GetHashCode(extraTypes);
        return code;
    }
}

public sealed class XmlSerializerIgnoringDefaultValuesKey : XmlSerializerWithExtraTypesKey
{
    readonly XmlAttributeOverrides overrides;

    private XmlSerializerIgnoringDefaultValuesKey(Type serializerType,IEnumerable<Type> ignoreDefaultTypes,XmlAttributeOverrides overrides)
        : base(serializerType,ignoreDefaultTypes)
    {
        this.overrides = overrides;
    }

    public static XmlSerializerIgnoringDefaultValuesKey Create(Type serializerType,bool recurse)
    {
        XmlAttributeOverrides overrides;
        Type [] typesWithOverrides;

        CreateOverrideAttributes(ignoreDefaultTypes,recurse,out overrides,out typesWithOverrides);
        return new XmlSerializerIgnoringDefaultValuesKey(serializerType,typesWithOverrides,overrides);
    }

    protected override XmlSerializer CreateSerializer()
    {
        var types = ExtraTypes;
        if (types == null || types.Length < 1)
            return new XmlSerializer(SerializedType);
        return new XmlSerializer(SerializedType,overrides);
    }

    static void CreateOverrideAttributes(IEnumerable<Type> types,bool recurse,out XmlAttributeOverrides overrides,out Type[] typesWithOverrides)
    {
        HashSet<Type> visited = new HashSet<Type>();
        HashSet<Type> withOverrides = new HashSet<Type>();
        overrides = new XmlAttributeOverrides();

        foreach (var type in types)
        {
            CreateOverrideAttributes(type,overrides,visited,withOverrides);
        }

        typesWithOverrides = withOverrides.ToArray();
    }

    static void AddOverride(XmlAttributeOverrides overrides,Type type,MemberInfo memberInfo)
    {
        var xmlElementAttr = memberInfo.GetCustomAttributes<XmlElementAttribute>();
        var xmlArrayAttr = memberInfo.GetCustomAttribute<XmlArrayAttribute>();
        var xmlArrayItemAttr = memberInfo.GetCustomAttributes<XmlArrayItemAttribute>();
        var attrs = new XmlAttributes 
        { 
            XmlDefaultValue = null,XmlArray = xmlArrayAttr,};
        foreach (var a in xmlElementAttr)
            attrs.XmlElements.Add(a);
        foreach (var a in xmlArrayItemAttr)
            attrs.XmlArrayItems.Add(a);
        overrides.Add(type,memberInfo.Name,attrs);
    }

    static void CreateOverrideAttributes(Type type,XmlAttributeOverrides overrides,HashSet<Type> visited,HashSet<Type> withOverrides)
    {
        if (type == null || type == typeof(object) || type.IsPrimitive || type == typeof(string) || visited.Contains(type))
            return;
        foreach (var property in type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public))
            if (overrides[type,property.Name] == null) // Check to see if overrides for this base type were already set.
                if (Attribute.IsDefined(property,typeof(DefaultValueAttribute),true))
                {
                    withOverrides.Add(type);
                    AddOverride(overrides,type,property);
                }
        foreach (var field in type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public))
            if (overrides[type,field.Name] == null) // Check to see if overrides for this base type were already set.
                if (Attribute.IsDefined(field,field);
                }
        visited.Add(type);
        if (recurse)
        {
            var baseType = type.BaseType;
            if (baseType != type)
                CreateOverrideAttributes(baseType,withOverrides);
        }
    }
}

演示小提琴here