I have a simple class as a test:
public class TEST
{
public string PropertyOne { get; set; }
public string PropertyTwo { get; set; }
}
I want to serialize this class to XML, but when I do; I want to specify at runtime how I want to serialize it. Only PropertyOne
, only PropertyTwo
or both.
I figured out you can achieve it normally by using the [XmlIgnore]
attribute on the properties that you don't want to serialize. I then tried the method explained here:
How to add property-level Attribute to the TypeDescriptor at runtime?
But for some reason it simply doesn't work. Here's my code:
TEST testInstance = new TEST();
testInstance.PropertyOne = "One";
testInstance.PropertyTwo = "Two";
SetAttributesToObjectOnProperty(testInstance, "PropertyOne");
using (StringWriter mainStringWriter = new StringWriter())
{
XmlSerializer mainXMLSerializer = new XmlSerializer(testInstance.GetType());
mainXMLSerializer.Serialize(mainStringWriter, testInstance);
string theXMLToWrite = mainStringWriter.ToString();
}
public static void SetAttributesToObjectOnProperty(object classInstanceToCheck, string propertyName)
{
if (propertyName != null && classInstanceToCheck != null)
{
// Prepare the Property Overriding Type Descriptor
PropertyOverridingTypeDescriptor mainPropertyOverridingTypeDescriptor = new PropertyOverridingTypeDescriptor(TypeDescriptor.GetProvider(classInstanceToCheck).GetTypeDescriptor(classInstanceToCheck));
// Iterate through properies in the supplied Object / Type
foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(classInstanceToCheck))
{
if (propertyDescriptor.Name == propertyName)
{
System.Xml.Serialization.XmlIgnoreAttribute theXMLIgnoreAttributToAdd = new System.Xml.Serialization.XmlIgnoreAttribute();
PropertyDescriptor newPropertyDescriptor = TypeDescriptor.CreateProperty(classInstanceToCheck.GetType(), propertyDescriptor, theXMLIgnoreAttributToAdd);
// Set the new PropertyOverridingTypeDescriptor to override that property
mainPropertyOverridingTypeDescriptor.OverrideProperty(newPropertyDescriptor);
break;
}
}
// Add the new descriptor provider that will return our descriptor instead of default
TypeDescriptor.AddProvider(new TypeDescriptorOverridingProvider(mainPropertyOverridingTypeDescriptor), classInstanceToCheck);
}
}
public static void SetAttributesToObjectOnProperty(object classInstanceToCheck, string propertyName)
{
try
{
if (propertyName != null)
{
// Prepare the Property Overriding Type Descriptor
PropertyOverridingTypeDescriptor mainPropertyOverridingTypeDescriptor = new PropertyOverridingTypeDescriptor(TypeDescriptor.GetProvider(classInstanceToCheck).GetTypeDescriptor(classInstanceToCheck));
// Iterate through properies in the supplied Object / Type
foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(classInstanceToCheck))
{
if (propertyDescriptor.Name == propertyName)
{
System.Xml.Serialization.XmlIgnoreAttribute theXMLIgnoreAttributToAdd = new System.Xml.Serialization.XmlIgnoreAttribute();
PropertyDescriptor newPropertyDescriptor = TypeDescriptor.CreateProperty(classInstanceToCheck.GetType(), propertyDescriptor, theXMLIgnoreAttributToAdd);
// Set the new PropertyOverridingTypeDescriptor to override that property
mainPropertyOverridingTypeDescriptor.OverrideProperty(newPropertyDescriptor);
break;
}
}
// Add the new descriptor provider that will return our descriptor instead of default
TypeDescriptor.AddProvider(new TypeDescriptorOverridingProvider(mainPropertyOverridingTypeDescriptor), classInstanceToCheck);
}
}
catch (Exception ex)
{
MessageBox.Show("Error at 'SetAttributesToObjectOnProperty'" + Environment.NewLine + Environment.NewLine + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
public class PropertyOverridingTypeDescriptor : CustomTypeDescriptor
{
// Fields
private readonly Dictionary<string, PropertyDescriptor> OverridePropertyDescriptors = new Dictionary<string, PropertyDescriptor>();
// Constructor
public PropertyOverridingTypeDescriptor(ICustomTypeDescriptor parent) : base(parent) { }
// Methods
public void OverrideProperty(PropertyDescriptor thePropertyDescriptor)
{
try
{
OverridePropertyDescriptors[thePropertyDescriptor.Name] = thePropertyDescriptor;
}
catch (Exception ex)
{
MessageBox.Show("Error at 'OverrideProperty'" + Environment.NewLine + Environment.NewLine + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
public override object GetPropertyOwner(PropertyDescriptor thePropertyDescriptor)
{
try
{
object toReturn = base.GetPropertyOwner(thePropertyDescriptor);
if (toReturn == null)
{
return this;
}
return toReturn;
}
catch (Exception ex)
{
MessageBox.Show("Error at 'GetPropertyOwner'" + Environment.NewLine + Environment.NewLine + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return null;
}
}
public PropertyDescriptorCollection GetPropertiesMain(PropertyDescriptorCollection thePropertyDescriptorCollection)
{
try
{
List<PropertyDescriptor> mainPropertyDescriptorList = new List<PropertyDescriptor>(thePropertyDescriptorCollection.Count + 1);
foreach (PropertyDescriptor propertyDescriptor in thePropertyDescriptorCollection)
{
if (OverridePropertyDescriptors.ContainsKey(propertyDescriptor.Name))
{
mainPropertyDescriptorList.Add(OverridePropertyDescriptors[propertyDescriptor.Name]);
}
else
{
mainPropertyDescriptorList.Add(propertyDescriptor);
}
}
PropertyDescriptorCollection toReturn = new PropertyDescriptorCollection(mainPropertyDescriptorList.ToArray());
return toReturn;
}
catch (Exception ex)
{
MessageBox.Show("Error at 'GetPropertiesMain'" + Environment.NewLine + Environment.NewLine + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return null;
}
}
public override PropertyDescriptorCollection GetProperties()
{
try
{
return GetPropertiesMain(base.GetProperties());
}
catch (Exception ex)
{
MessageBox.Show("Error at 'GetProperties'" + Environment.NewLine + Environment.NewLine + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return null;
}
}
public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
try
{
return GetPropertiesMain(base.GetProperties(attributes));
}
catch (Exception ex)
{
MessageBox.Show("Error at 'GetProperties'" + Environment.NewLine + Environment.NewLine + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return null;
}
}
}
public class TypeDescriptorOverridingProvider : TypeDescriptionProvider
{
// Fields
private readonly ICustomTypeDescriptor MainCustomTypeDescriptor;
// Constructor
public TypeDescriptorOverridingProvider(ICustomTypeDescriptor theCustomTypeDescriptor)
{
try
{
this.MainCustomTypeDescriptor = theCustomTypeDescriptor;
}
catch (Exception ex)
{
MessageBox.Show("Error at Constructor 'TypeDescriptorOverridingProvider'" + Environment.NewLine + Environment.NewLine + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
// Methods
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
try
{
return MainCustomTypeDescriptor;
}
catch (Exception ex)
{
MessageBox.Show("Error at 'GetTypeDescriptor'" + Environment.NewLine + Environment.NewLine + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return null;
}
}
}
There are no exceptions, it just still serializes both.
I don't know if I'm not using this method correctly or if I'm missing something else here.
I would like to use this method on other bigger classifications and try use other XML Attributes as well.