如何解决:“你需要XmlChoiceIdentifierAttribute添加到成员。”使用XmlAttributeOverrides什么时候?

问题描述 投票:1回答:1

我试图用XmlAttributeOverrides改变我的课被序列化到XML的方式。我需要排除一些属性,包括人在一个特定的顺序。

我这里有这样的代码:

// XML Attribute Overrrides
public static XmlAttributeOverrides GetXMLAttributeOverrides(Type theType, List<string> propertiesToInlcudeInOrder, List<string> allColumnNames)
{
    try
    {
        if (propertiesToInlcudeInOrder != null)
        {
            XmlAttributeOverrides theXMLAttributeOverrides = new XmlAttributeOverrides();
            if (propertiesToInlcudeInOrder.Count > 0)
            {
                XmlAttributes mainNewXMLAttributes = new XmlAttributes();
                mainNewXMLAttributes.XmlIgnore = false;

                XmlAttributes ignoreXMLAttributes = new XmlAttributes();
                ignoreXMLAttributes.XmlIgnore = true;

                List<string> propertiesToNotInclude = new List<string>();
                foreach (string theColumnName in allColumnNames)
                {
                    string thePropertyName = theColumnName;
                    bool addProperty = true;
                    foreach (string propertyToInclude in propertiesToInlcudeInOrder)
                    {
                        if (thePropertyName == propertyToInclude)
                        {
                            addProperty = false;
                            break;
                        }
                    }

                    if (addProperty)
                    {
                        propertiesToNotInclude.Add(thePropertyName);
                    }
                }

                // To Ignore
                foreach (string propertyNameToNotInlcude in propertiesToNotInclude)
                {
                    XmlElementAttribute theXMLElementAttributeToAdd = new XmlElementAttribute(propertyNameToNotInlcude);
                    theXMLElementAttributeToAdd.ElementName = propertyNameToNotInlcude;
                    ignoreXMLAttributes.XmlElements.Add(theXMLElementAttributeToAdd);

                    theXMLAttributeOverrides.Add(theType, propertyNameToNotInlcude, ignoreXMLAttributes);
                }

                // To Add In Order
                int counter = 1;
                foreach (string propertyNameToIncludeInOrder in propertiesToInlcudeInOrder)
                {
                    XmlElementAttribute theXMLElementAttributeToAdd = new XmlElementAttribute(propertyNameToIncludeInOrder);
                    theXMLElementAttributeToAdd.ElementName = propertyNameToIncludeInOrder;
                    theXMLElementAttributeToAdd.Order = counter;
                    mainNewXMLAttributes.XmlElements.Add(theXMLElementAttributeToAdd);

                    theXMLAttributeOverrides.Add(theType, propertyNameToIncludeInOrder, mainNewXMLAttributes);

                    counter++;
                }
            }

            return theXMLAttributeOverrides;
        }
        else
        {
            return null;
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("Error at 'GetXMLAttributeOverrides'" + Environment.NewLine + Environment.NewLine + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
        return null;
    }
}

在我的测试中,我有13个属性的类,我想在一个特定的顺序3,并排除所有其他人。

我已经确信,我没有任何重复在我的名单。我有双重检查,我没有在“黑名单”具有相同的属性名称和“包括列表”。我就在这行我的代码的异常:XmlSerializer(dataToSerialize.GetType(), allXMLAttribueOverrides);

allXMLAttribueOverrides从我的方法GetXMLAttributeOverrides返回

唯一的例外是:

有反射型“System.Collections.Generic.List`1 [SystemName.UserControls.TestMain]”的误差。

内部异常是:

有反射性的错误“TextColumn”。

您需要XmlChoiceIdentifierAttribute添加到“TextColumn”成员。

“TextColumn”是在我的测试类中的第一个属性

这里是我的测试代码:

TestMain testItem = new TestMain(null, "TextColumnTEST", 5, Convert.ToDecimal(0.333), Convert.ToDecimal(0.777), DateTime.Now, "12:00:00", DateTime.Now, true, "Password", "#FFFFFF", null, null, null);
List<TestMain> dataToSerialize = new List<TestMain>();
dataToSerialize.Add(testItem);

List<string> propertiesToInlcudeInOrder = new List<string>();
propertiesToInlcudeInOrder.Add("CurrencyColumn");
propertiesToInlcudeInOrder.Add("NumberColumn");
propertiesToInlcudeInOrder.Add("TextColumn");

List<string> allColumnNames = new List<string>();
allColumnNames.Add("ID");
allColumnNames.Add("Select");
allColumnNames.Add("TextColumn");
allColumnNames.Add("NumberColumn");
allColumnNames.Add("CurrencyColumn");
allColumnNames.Add("DecimalColumn");
allColumnNames.Add("DateColumn");
allColumnNames.Add("TimeColumn");
allColumnNames.Add("DateAndTimeColumn");
allColumnNames.Add("YesNoColumn");
allColumnNames.Add("PasswordColumn");
allColumnNames.Add("ColorColumn");
allColumnNames.Add("ImageColumn");
allColumnNames.Add("DocumentColumn");
allColumnNames.Add("OtherColumn");

XmlAttributeOverrides allXMLAttribueOverrides = ReportingManipulation.GetXMLAttributeOverrides(dataToSerialize[0].GetType(), propertiesToInlcudeInOrder, allColumnNames);

using (StringWriter mainStringWriter = new StringWriter())
{
    XmlSerializer mainXMLSerializer = new XmlSerializer(dataToSerialize.GetType(), allXMLAttribueOverrides);
    mainXMLSerializer.Serialize(mainStringWriter, dataToSerialize);
    return mainStringWriter.ToString();
}

这是我的测试类:

public class TestMain
{
    #region Properties

    // Properties

    [XmlIgnore]
    public int? ID { get; set; }
    [XmlIgnore]
    public bool Select { get; set; }

    public string TextColumn { get; set; }
    public int NumberColumn { get; set; }
    public decimal CurrencyColumn { get; set; }
    public decimal DecimalColumn { get; set; }
    public DateTime DateColumn { get; set; }
    public string TimeColumn { get; set; }
    public DateTime DateAndTimeColumn { get; set; }
    public bool YesNoColumn { get; set; }
    public string PasswordColumn { get; set; }
    public string ColorColumn { get; set; }
    public byte[] ImageColumn { get; set; }
    public byte[] DocumentColumn { get; set; }
    public byte[] OtherColumn { get; set; }

    #endregion

    #region Constructors

    // Constructors
    public TestMain()
    {
        try
        {

        }
        catch (Exception ex)
        {
            MessageBox.Show("Error at Constructor: 'TestMain'" + Environment.NewLine + Environment.NewLine + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
        }
    }
    public TestMain(int? theID, string theTextColumn, int theNumberColumn, decimal theCurrencyColumn, decimal theDecimalColumn, DateTime theDateColumn, string theTimeColumn, DateTime theDateAndTimeColumn, bool theYesNoColumn, string thePasswordColumn, string theColorColumn, byte[] theImageColumn, byte[] theDocumentColumn, byte[] theOtherColumn)
    {
        try
        {
            this.ID = theID;

            this.TextColumn = theTextColumn;
            this.NumberColumn = theNumberColumn;
            this.CurrencyColumn = theCurrencyColumn;
            this.DecimalColumn = theDecimalColumn;
            this.DateColumn = theDateColumn;
            this.TimeColumn = theTimeColumn;
            this.DateAndTimeColumn = theDateAndTimeColumn;
            this.YesNoColumn = theYesNoColumn;
            this.PasswordColumn = thePasswordColumn;
            this.ColorColumn = theColorColumn;
            this.ImageColumn = theImageColumn;
            this.DocumentColumn = theDocumentColumn;
            this.OtherColumn = theOtherColumn;
        }
        catch (Exception ex)
        {
            MessageBox.Show("Error at Constructor: 'TestMain'" + Environment.NewLine + Environment.NewLine + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
        }
    }

    #endregion
}

我要去哪里错了?

任何帮助/建议将不胜感激。

c# xml serialization xml-serialization xmlserializer
1个回答
2
投票

你的基本问题是,你要添加多重覆盖的每个属性的属性[XmlElement],因为你正在使用的所有的人的一个实例mainNewXMLAttributes,其累积为所有这些定义的XmlElementAttribute对象。

为了解决这个问题,你需要分配一个新的mainNewXMLAttributesforeach (var propertyNameToIncludeInOrder in propertiesToInlcudeInOrder)循环内的每个属性,如图GetXMLAttributeOverrides()以下修正和简化版本:

public static partial class ReportingManipulation
{
    public static XmlAttributeOverrides GetXMLAttributeOverrides(Type theType, IList<string> propertiesToInlcudeInOrder)
    {
        var allProperties = theType.GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance).Select(p => p.Name);
        return GetXMLAttributeOverrides(theType, propertiesToInlcudeInOrder, allProperties);
    }

    // XML Attribute Overrrides
    public static XmlAttributeOverrides GetXMLAttributeOverrides(Type theType, IList<string> propertiesToInlcudeInOrder, IEnumerable<string> allProperties)
    {
        if (propertiesToInlcudeInOrder == null || propertiesToInlcudeInOrder.Count == 0)
            return null;

        var theXMLAttributeOverrides = new XmlAttributeOverrides();

        // To Add In Order
        int counter = 1;
        foreach (var propertyNameToIncludeInOrder in propertiesToInlcudeInOrder)
        {
            // Allocate a fresh instance of XmlAttributes for each property, because we are defining a different
            // XmlElementAttribute for each
            var mainNewXMLAttributes = new XmlAttributes { XmlIgnore = false };

            // Specify the element order XmlElementAttribute and attach to the XmlAttributes
            var theXMLElementAttributeToAdd = new XmlElementAttribute { Order = counter };
            mainNewXMLAttributes.XmlElements.Add(theXMLElementAttributeToAdd);

            // Attach the override XmlElementAttribute to the property propertyNameToIncludeInOrder
            theXMLAttributeOverrides.Add(theType, propertyNameToIncludeInOrder, mainNewXMLAttributes);

            counter++;
        }

        // To Ignore
        // Using System.Linq.Enumerable.Except()
        var propertiesToNotInclude = allProperties.Except(propertiesToInlcudeInOrder);
        var ignoreXMLAttributes = new XmlAttributes { XmlIgnore = true };
        foreach (var propertyNameToNotInlcude in propertiesToNotInclude)
        {
            // Attach the override XmlElementAttribute to the property propertyNameToIncludeInOrder
            // No need to allocate a fresh instance of ignoreXMLAttributes for each, because the instances would all be identical
            theXMLAttributeOverrides.Add(theType, propertyNameToNotInlcude, ignoreXMLAttributes);
        }

        return theXMLAttributeOverrides;
    }
}

为什么你的代码不能正常工作?在您最初的代码,你这样做:

XmlAttributes mainNewXMLAttributes = new XmlAttributes();
mainNewXMLAttributes.XmlIgnore = false;

int counter = 1;
foreach (string propertyNameToIncludeInOrder in propertiesToInlcudeInOrder)
{
    XmlElementAttribute theXMLElementAttributeToAdd = new XmlElementAttribute(propertyNameToIncludeInOrder);
    theXMLElementAttributeToAdd.ElementName = propertyNameToIncludeInOrder;
    theXMLElementAttributeToAdd.Order = counter;
    mainNewXMLAttributes.XmlElements.Add(theXMLElementAttributeToAdd);

    theXMLAttributeOverrides.Add(theType, propertyNameToIncludeInOrder, mainNewXMLAttributes);

    counter++;
}

现在,该方法XmlAttributeOverrides.Add(Type, String, XmlAttributes)被记录为如下工作:

添加一个XmlAttributes对象XmlAttributes对象的集合。所述type参数指定的对象被重写。所述member参数指定覆盖的部件的名称。

因此mainNewXMLAttributes的内容将得到应用到指定的参数时,XmlSerializer最终构造。而当你构建mainNewXMLAttributes的唯一实例的所有参数,其XmlElements数组将包含对应于所有参数的元素名称!即你的代码尝试应用多种[XmlElement]属性每个命名参数,仅在替代名称和顺序不同。这占了你需要XmlChoiceIdentifierAttribute添加到“TextColumn”成员。例外 - 你只能多元素名称附加到一个属性,如果属性值是多态的,你想指定不同的元素名称不同的值类型。

笔记

  • 当产生与覆盖的XmlSerializer,你必须静态缓存,稍后再重新使用,以避免严重的内存泄露,如Memory Leak using StreamReader and XmlSerializer解释。
  • 我不建议无条件地吞咽异常,并把他们当作错误消息在低级别的实用方法或对象构造用户。

演示工作小提琴here

© www.soinside.com 2019 - 2024. All rights reserved.