I have a ApplicationSettingsBase object I use to save user preferences, as well as application settings. For all of my built-in types, it properly serializes to XML and I get a nice user-editable config file. However, for my custom type "RuleCollection", this doesn't work, the only way for me to serialize it is binary which is nonsense to the user.
I have tried from the following links without success:
Add a collection of a custom class to Settings.Settings -- I originally was trying to serialize a CleanRule[] as I was able to serialize a string[] without issue. Adding the collection class as a wrapper was a band-aid that didn't work.
Custom Xml Serialization of Unknown Type and Implementing Custom XML Serialization/Deserialization of compound data type? -- I wasn't able to make settings.Save() trigger the custom XML Read/Write classes from implementing IXmlSerializable
, I think if I could force it to, this would work.
What I'm hoping for is a nice XML output where I have something like
-> Collection
-> Rule 1
-> Title
-> Description
-> Enabled
-> Mode
-> Regex
-> Args
-> Arg1
-> Arg2
-> Rule 2
-> Title
-> Description
-> Enabled
-> Mode
-> Regex
-> Args
-> Arg1
I am using .NET Framework 4.7.2
public class UserSettings : ApplicationSettingsBase
{
[UserScopedSetting]
[SettingsSerializeAs(SettingsSerializeAs.Binary)]
public RuleCollection Rules
{
get { return (RuleCollection)this["Rules"]; }
set { this["Rules"] = value; }
}
... //other properties
}
Below is the properties of the RuleCollection
and CleanRule
classes, CleanMode
is an `Enum
[Serializable]
[SettingsSerializeAs(SettingsSerializeAs.Xml)]
public class CleanRule
{
public string Title { get; private set; }
public string Description { get; private set; }
public bool Enabled { get; private set; } = true;
public CleanMode Mode { get; private set; }
public Regex R { get; private set; }
public string[] Args { get; private set; }
... //constructors and other methods
}
[Serializable]
[SettingsSerializeAs(SettingsSerializeAs.Xml)]
public class RuleCollection : IEnumerable<CleanRule>
{
public List<CleanRule> Rules { get; set; }
... // constructors and other methods
}
Finally, I am editing and saving the property like so
settings = new UserSettings();
settings.Rules = settings.Rules ?? new RuleCollection();
settings.Save();
and
RuleForm rf = new RuleForm(settings.Rules);
if(rf.ShowDialog(this) == DialogResult.OK)
{
settings.Rules = rf.Rules;
settings.Save();
}
EDIT: I've boiled this down to a more simple example EDIT 2: This example now works, it was missing a no-arg constructor as per How to serialize a class with a list of custom objects? My main code is still not working, but it would appear that serialization errors are being masked by the ApplicationSettingsBase class
public class UserSettings : ApplicationSettingsBase
{
[UserScopedSetting]
public Test Test
{
get { return (Test)this["Test"]; }
set { this["Test"] = value; }
}
}
[Serializable]
public class Test
{
public int I { get; set; }
public string S { get; set; }
public Test(){ }
public Test(int i, string s)
{
I = i;
S = s;
}
}
settings = new UserSettings();
settings.Test = new Test(30, "Tom");
settings.Save();
Result:
<setting name="Test" serializeAs="Xml">
<value>
<Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<I>30</I>
<S>Tom</S>
</Test>
</value>
</setting>
TL:DR; there were a bunch of little things wrong that SHOULD HAVE been raised as exceptions, however, due to using the ApplicationSettingsBase class, serialization errors were being suppressed.
I found a post that gave me explicit "write to" and "read from" xml file for a generic type
<T>
and used that to force the object I was having trouble with to xml and raise those errors.The first error had to do with my collection function inheriting from IEnumerable but not implementing Add()
The second error was that my classes attributes had private setters. I'm not crazy about those being public but I guess that's just what has to happen.
And I'm still working on the third error, which is serialization of a Regex object.