我试图用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
}
我要去哪里错了?
任何帮助/建议将不胜感激。
你的基本问题是,你要添加多重覆盖的每个属性的属性[XmlElement]
,因为你正在使用的所有的人的一个实例mainNewXMLAttributes
,其累积为所有这些定义的XmlElementAttribute
对象。
为了解决这个问题,你需要分配一个新的mainNewXMLAttributes
为foreach (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。