CSharp - 如何通知XmlSerializer使用 [DefautValue(...)] 序列化属性?

  显示原文与译文双语对照的内容
0 0

我正在使用 DefaultValue属性才能正确 PropertyGrid行为( 它显示了值不同于缺省值以粗体显示) 。 现在如果我想对显示对象进行序列化的使用。 XmlSerializerxml文件中就没有项的属性使用默认值。

告知XmlSerializer来序列化这些还是最简单的方法是什么

这里需要支持" 版本",所以当我更改默认值后面的代码它有序列化与序列化属性获取值,而不是" 最新" 一个。 我能想到的就是:

  • 重写行为。 PropertyGrid( 使用自定义属性,这样你就能ignoreed 。 XmlSerializer) ;
  • 自定义xml序列化,而忽略所做事情的 DefaultValue为;
  • 对对象进行一些处理,然后将其传递给 XmlSeriazer因此它将不包含 DefaultValue是了。

但是还有机会我請你們secret属性允许以不疼=D就做什么。

在下面的章节中我想要:

    private bool _allowNegative = false;
    /// <summary>
    /// Get or set if negative results are allowed
    /// </summary>
    [Category(CategoryAnalyse)]
    [Admin]
    [TypeConverter(typeof(ConverterBoolOnOff))]
    //[DefaultValue(false)] *1
    public bool AllowNegative
    {
        get { return _allowNegative; }
        set
        {
            _allowNegative = value;
            ConfigBase.OnConfigChanged();
        }
    }
    //public void ResetAllowNegative() { _allowNegative = false; } *2
    //public bool ShouldSerializeAllowNegative() { return _allowNegative; } *3
    //public bool ShouldSerializeAllowNegative() { return true; } *4

如果我取消注释中( *1 ),那我就想要的效果 PropertyGrid属性的默认值显示为普通文本,如果没有文本是否为粗体。 但是 XmlSerializer将具有默认值属性置于XML文件这是 BAD ( 和我试图改变它) 。

如果我注释掉( *2 ) 和( *3中一样),则它被完全取消( *1 ) 。

如果我注释掉( *2 ) 和( *4 ),则 XmlSerializer总是将属性放入xml文件中,但这是因为他们不再 没有默认的值,PropertyGrid以粗体文本显示的所有值。

时间:原作者:6个回答

0 0

只要你不需要属性中Xml,如果使用 DataContractSerializer 相反就会得到你想要的行为。

[DataContract]
public class Test
{
    [DataMember]
    [DefaultValue(false)]
    public bool AllowNegative { get; set; }
}
void Main()
{
    var sb2 = new StringBuilder();
    var dcs = new DataContractSerializer(typeof(Test));
    using(var writer = XmlWriter.Create(sb2))
    {
        dcs.WriteObject(writer, new Test());
    }
    Console.WriteLine(sb2.ToString());  
}

produces ( 减去命名空间等)

<Test>
    <AllowNegative>false</AllowNegative>
</Test>
原作者:
0 0

可以使用两个属性:

// For property grid only:
[Category(CategoryAnalyse)]
[TypeConverter(typeof(ConverterBoolOnOff))]
[DefaultValue(false)]
[XmlIgnore]
public bool AllowNegative
{
    get { return _allowNegative; }
    set
    {
        _allowNegative = value;
        ConfigBase.OnConfigChanged();
    }
}
// For serialization:
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
[TypeConverter(typeof(ConverterBoolOnOff))]
[XmlElement("AllowNegative")]
public bool AllowNegative_XML
{
    get { return _allowNegative; }
    set
    {
        _allowNegative = value;
        ConfigBase.OnConfigChanged();
    }
}
原作者:
0 0

我想你需要的是什么ShouldSerialize()Reset()。 使用这些更多地扩展你的类a ( 使用每个属性),不过,它实现了两个函数专门用来查找。

下面是一个简短的例子:

// your property variable
private const String MyPropertyDefault = "MyValue";
private String _MyProperty = MyPropertyDefault;
// your property
// [DefaultValueAttribute("MyValue")] - cannot use DefaultValue AND ShouldSerialize()/Reset()
public String MyProperty
{
    get { return _MyProperty; }
    set { _MyProperty = value; }
}
// IMPORTANT!
// notice that the function name is "ShouldSerialize..." followed
// by the exact (!) same name as your property
public Boolean ShouldSerializeMyProperty()
{
    // here you would normally do your own comparison and return true/false
    // based on whether the property should be serialized, however,
    // in your case, you want to always return true when serializing!
    // IMPORTANT CONDITIONAL STATEMENT!
    if (!DesignMode)
        return true; // always return true outside of design mode (is used for serializing only)
    else
        return _MyProperty != MyPropertyDefault; // during design mode, we actually compare against the default value
}
public void ResetMyProperty()
{
    _MyProperty = MyPropertyDefault;
}

请注意,由于希望保持PropertyGrid策略中的功能,则必须究竟是否进行序列化,则当 ShouldSerialize()函数被调用。 我建议你实现某种形式的控制标志,用于获取设置序列化,因此时总是return true


请注意,你无法 使用DefaultValue属性结合使用, ShouldSerialize()Reset()函数( 只使用其中一个或者 ) 。


EDIT : Adding澄清。 ShouldSerialize()函数。

因为目前没有方法序列化默认值并告知" PropertyGrid属性都有其默认值,则必须实现一个条件检查是否处于设计模式。

假设你的类派生自 ComponentControl,你有 DesignMode属性,这可以通过在设计时Visual Studio 只有 。 条件中如下所示:

if (!DesignMode)
    return true; // always return true outside of design mode (is used for serializing only)
else
    return _MyProperty != MyPropertyDefault; // during design mode, we actually compare against the default value

EDit 2: 我们不是在讨论 Visual Studio的设计模式。

考虑到上面的代码中,创建另一个属性名为 IsSerializing. 设置 IsSerializing属性设置为 true之前调用 XmlSerializer.Serialize以及取消其 之后。

最后,更改 if (!DesignMode)条件语句为 if (IsSerializing).

原作者:
0 0

这种行为的 XmlSerializer可以作为一个ascii文件创建与 XmlAttributeOverrides

我借用了这个想法从这里

static public XmlAttributeOverrides GetDefaultValuesOverrides(Type type)
{
    XmlAttributeOverrides explicitOverrides = new XmlAttributeOverrides();
    PropertyDescriptorCollection c = TypeDescriptor.GetProperties(type);
    foreach (PropertyDescriptor p in c)
    {
        AttributeCollection attributes = p.Attributes;
        DefaultValueAttribute defaultValue = (DefaultValueAttribute)attributes[typeof(DefaultValueAttribute)];
        XmlIgnoreAttribute noXML = (XmlIgnoreAttribute)attributes[typeof(XmlIgnoreAttribute)];
        XmlAttributeAttribute attribute = (XmlAttributeAttribute)attributes[typeof(XmlAttributeAttribute)];
        if ( defaultValue != null && noXML == null )
        {
            XmlAttributeAttribute xmlAttribute = new XmlAttributeAttribute(attribute.AttributeName);
            XmlAttributes xmlAttributes = new XmlAttributes();
            xmlAttributes.XmlAttribute = xmlAttribute;
            explicitOverrides.Add(userType, attribute.AttributeName, xmlAttributes);
        }
    }
    return explicitOverrides;
}

并让我自己一个一个Attribute修饰的类应该会随之发出默认值。 如果希望对所有类都这么做,我相信你一定可以调整整个概念。

Public Class EmitDefaultValuesAttribute
    Inherits Attribute
    Private Shared mCache As New Dictionary(Of Assembly, XmlAttributeOverrides)
    Public Shared Function GetOverrides(assembly As Assembly) As XmlAttributeOverrides
        If mCache.ContainsKey(assembly) Then Return mCache(assembly)
        Dim xmlOverrides As New XmlAttributeOverrides
        For Each t In assembly.GetTypes()
            If t.GetCustomAttributes(GetType(EmitDefaultValuesAttribute), True).Count > 0 Then
                AddOverride(t, xmlOverrides)
            End If
        Next
        mCache.Add(assembly, xmlOverrides)
        Return xmlOverrides
    End Function
    Private Shared Sub AddOverride(t As Type, xmlOverrides As XmlAttributeOverrides)
        For Each prop In t.GetProperties()
            Dim defaultAttr = prop.GetCustomAttributes(GetType(DefaultValueAttribute), True).FirstOrDefault()
            Dim xmlAttr As XmlAttributeAttribute = prop.GetCustomAttributes(GetType(XmlAttributeAttribute), True).FirstOrDefault()
            If defaultAttr IsNot Nothing AndAlso xmlAttr IsNot Nothing Then
                Dim attrs As New XmlAttributes '= {New XmlAttributeAttribute}
                attrs.XmlAttribute = xmlAttr
                ''overide.Add(t, xmlAttr.AttributeName, attrs)
                xmlOverrides.Add(t, prop.Name, attrs)
            End If
        Next
    End Sub

因为 xsd.exe产生分部类(PartialClasses)可以添加。 EmitDefaultValuesAttribute在将文件分离开:

<EmitDefaultValuesAttribute()>
Public MyClass
    Public Property SubClass() As MySubClass
End Class
<EmitDefaultValuesAttribute()>
Public MySubClass
End Class

用法如下:

Dim serializer As New XmlSerializer(GetType(MyClass), EmitDefaultValuesAttribute.GetOverrides(GetType(MyClass).Assembly))
原作者:
...