3

I want the ability to reset a single user setting easily to its default value. I've written an extension like so:

public static void sReset(this Properties.Settings set, string key = "")
{
    if (key == "")
    {
        set.Reset();
        return;
    }
    Console.WriteLine("Reset '" + key + "' to: " + set.Properties[key].DefaultValue);
    set.PropertyValues[key].PropertyValue = set.PropertyValues[key].Property.DefaultValue;
}

And this works fine for primitive types. But now I want to apply that to a stringCollection, and it fails:

An unhandled exception of type 'System.InvalidCastException' occurred in myApp.exe

Additional information: Unable to cast object of type 'System.String' to type 'System.Collections.Specialized.StringCollection'.

This is because these collection type default values (Stored serialized as XML) are returned as strings: set.Properties[key].DefaultValue.GetType() returns System.String

I can see in the settings designer that usually, it just casts the value to StringCollection:

public global::System.Collections.Specialized.StringCollection settingsName {
    get {
        return ((global::System.Collections.Specialized.StringCollection)(this["settingsName"]));
    }
    set {
        this["settingsName"] = value;
    }
}

But that fails after assigning the DefaultValue, with the above error message.

I tried casting the XML String before assigning, but of course that failed there, too.

How is an XML String like this converted before being assigned to the settings property? What do I need to do to make this work?

2 Answers 2

1

Nobody? That sucks, I would've thought there was a more elegant solution...

So I'm using this now:

  1. Check if the Type of the setting is StringCollection

  2. Read out XML Elements at "ArrayOfString/string"

... <-- wouldn't let me format code as code without an additional paragraph here. What the hell?

public static void sReset(this Properties.Settings set, string key = "")
{
    if (key == "")
    {
        set.Reset();
        return;
    }
    if (set.PropertyValues[key].Property.PropertyType == typeof(StringCollection))
    {
        string tvs = (string)set.PropertyValues[key].Property.DefaultValue;
        set.PropertyValues[key].PropertyValue = tvs.XmlToStringCollection();
        return;
    }
    set.PropertyValues[key].PropertyValue = set.PropertyValues[key].Property.DefaultValue;
}

public static StringCollection XmlToStringCollection(this string str)
{
    StringCollection ret = new StringCollection();

    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.LoadXml(str);
    XmlNodeList terms = xmlDoc.SelectNodes("ArrayOfString/string");

    foreach (XmlElement s in terms)
    {
        if (s.InnerXml != "")
        {
            Console.WriteLine("Found: " + s.InnerXml);
            ret.Add(s.InnerXml);
        }
    }
    return ret;
}

since the XML looks like this:

<?xml version="1.0" encoding="utf-16"?>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <string>first string</string>
  <string>second string</string>
  <string>...</string>
</ArrayOfString>

...Which is a shame, it's damn ugly and limited:

You'd have to do the same for any kind of XML serialized type

Really, what I'd like is a way to get the default value the same way VS does. I can't imagine it could be as hacky as this, could it?

Sign up to request clarification or add additional context in comments.

Comments

1

I realize this is an old question, but if anyone else lands here like I did, the OP's solution works. However, to answer OP's final question, I suspect Microsoft is using the XmlSerializer class, something like this extension method I came up with, though I also couldn't find a simple method call to do it for me:

    public static StringCollection ToStringCollection(this string str)
    {
        // Create an instance of the XmlSerializer.
        XmlSerializer serializer =
        new XmlSerializer(typeof(StringCollection));

        // Declare an object variable of the type to be deserialized.
        StringCollection sc;

        using (Stream reader = new MemoryStream(Encoding.Unicode.GetBytes(str)))
        {
            // Call the Deserialize method to restore the object's state.
            sc = (StringCollection)serializer.Deserialize(reader);
        }

        return sc;
    }

The above is based upon example code from https://learn.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlserializer.deserialize?view=net-6.0

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.