Home>

More precisely, the question is how to do this:

  • Fast;
  • In a few handy lines of code;
  • There and back, i.e. save and load on application startup;

It is advisable to save all this insettings(in short, objects from sheets will then be loaded into controls, edited from them, and then saved). The only problem is how to save them quickly and correctly.

  • Answer # 1

    I did serialization in Xml like this:

    public class MyClass
    {
        [XmlElement ("Name")]
        public string Name {get; set;} //This will be the element
        [XmlAttribute ("Value")]
        public string Value {get; set;} //This will be an attribute
        [XmlIgnore]
        public string ServiceField {get; set;} //We don't want to serialize /deserialize this field
    }
    public class MyClassCollection
    {
       [XmlArray ("Collection"), XmlArrayItem ("Item")]
       public List <
    MyClass >
     Collection {get; set;}
    }
    

    Then serialize:

    XmlSerializer xmlSerializer= new XmlSerializer (typeof (MyClassCollection));
    StringWriter stringWriter= new StringWriter ();
    xmlSerializer.Serialize (stringWriter, myClassCollection); //myClassCollection is our data
    

    Then we get xml as a string from the stream:

    string xml= stringWriter.ToString ();
    

    And deserialize:

    var xmlSerializer= new XmlSerializer (typeof (MyClassCollection));
    var stringReader= new StringReader (serializedData);
    MyClassCollection collection= (MyClassCollection) xmlSerializer.Deserialize (stringReader);
    

    Small clarifications:

    1. Fields for serialization must be with the public
    2. modifier
    3. If your field has a simple type (for example, string) and you want to make it an XmlElement, then it is not necessary to place XmlElement attributes, therefore sometimes it is enough to place XmlIgnore on those properties that we do not need in serialization /deserialization
    4. The
    5. XmlSerializer can sometimes throw a FileNotFoundException and this is considered normal behavior, so just ignore it. link, on SO, about this.

    Hope it helps.

    Thanks for the help! This is exactly what I need.

    Анна Киселёва2021-03-05 09:57:28

    +1, but why not in settings?

    VladD2021-03-05 09:57:28

    Once I asked here the question what is better to use, and I agree with the answer, therefore, not Settings. But this, of course, is just my opinion.

    Donil2021-03-05 09:57:28

    I disagree with the answer to the question you quoted. Settings are in a strictly defined place:% LOCALAPPDATA% \`, and of the two save /serialization options" manual "and automatic, I always prefer automatic. Compare how much simpler my code (Settings.Default.DataValues ​​= DataValues; Settings.Default.Save (); `) is compared to yours.

    VladD2021-03-05 09:57:28

    In my case, the choice is not in favor of Settings, because I needed to save collections of objects, not controls, for example.

    Анна Киселёва2021-03-05 09:57:28
  • Answer # 2

    The answers are excellent, plus both, but guys, the girl first asked for a convenient and fast way. But the result of your hint will be several classes containing their own serializer and cumbersome non-scalable code. Why not immediately show a beautiful version with an external serializer, then just bring it out to the Extension, for example:

    public static class SerializeExtension
            {
                public static string SerializeToString (this object obj)
                {
                    var xmlSerializer= new XmlSerializer (obj.GetType ());
                    var stringWriter= new StringWriter ();
                    xmlSerializer.Serialize (stringWriter, obj);
                    return stringWriter.ToString ();
                }
                public static T DeserializeString <
    T >
    (this string sourceString)
                {
                    var xmlSerializer= new XmlSerializer (typeof (T));
                    var stringReader= new StringReader (sourceString);
                    return (T) xmlSerializer.Deserialize (stringReader);
                }
            }
    

    and here is the xUnit test code to check the result:

    [Fact]
            public void FirstTest ()
            {
                var myClass= new MyClassCollection
                    {
                        Collection= new List <
    MyClass >
                            {
                                new MyClass {Name= "name1", Value= "val1", ServiceField= "bla bla"},
                                new MyClass {Name= "name2", Value= "val2", ServiceField= "bla bla"},
                                new MyClass {Name= "name3", Value= "val3", ServiceField= "bla bla"},
                                new MyClass {Name= "name4", Value= "val4", ServiceField= "bla bla"}
                            }
                    };
                var str= myClass.SerializeToString ();
                Console.WriteLine (str);
                var res= str.DeserializeString <
    MyClassCollection >
    ();
                Assert.Equal (res.Collection [0] .Name, "name1");
                Assert.Equal (res.Collection [1] .Name, "name2");
                Assert.Equal (res.Collection [2] .Name, "name3");
                Assert.Equal (res.Collection [3] .Name, "name4");
                Assert.Equal (res.Collection [0] .Value, "val1");
                Assert.Equal (res.Collection [1] .Value, "val2");
                Assert.Equal (res.Collection [2] .Value, "val3");
                Assert.Equal (res.Collection [3] .Value, "val4");
            }
    
  • Answer # 3

    The easiest way is to use the built-in classSettings... The only subtlety is that it takes a little hack to put the list in there.

    Here's the code:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using SettingsTest.Properties;
    namespace SettingsTest
    {
        class Program
        {
            static void Main (string [] args)
            {
                new Program (). RunData ();
            }
            List <
    Data >
     DataValues;
            void RunData ()
            {
                //read
                DataValues ​​= Settings.Default.DataValues;
                Console.WriteLine ("Stored values:");
                if (DataValues!= null)
                {
                    foreach (var d in DataValues)
                        Console.WriteLine (d);
                }
                //modify
                Console.Write ("Input int values ​​separated by space:");
                var input= Console.ReadLine ();
                DataValues ​​= input.Split ()
                                  .Select (int.Parse)
                                  .Select (i= >
     new Data ()
                                               {
                                                   X= i,
                                                   L= new List <
    int >
    () {i -1, i + 1}
                                               })
                                  .ToList ();
                //write back
                Settings.Default.DataValues ​​= DataValues;
                Settings.Default.Save ();
            }
        }
        [Serializable]
        public class Data
        {
            public int X {get; set; }
            public List <
    int >
     L {get; set; }
            public override string ToString ()
            {
                return string.Format ("Data (X= {0}, L= <
    {1} >
    ) ", X, string.Join (", ", L));
            }
        }
    }
    

    To put a list inSettings, do it like this:

    1. Open project properties
    2. Go to the Settings tab. If your project doesn't have Settings yet, add them.
    3. Add a property with the desired name (DataValues). You will not be able to select the type you want (List < Data >), so select e.g. string.
    4. Go to the project directory and find the file thereProperties \ Settings.settings... Open it in an editor, find the line< Setting Name= "DataValues" ...and manually change the value of the type to the desired one:Type= "System.Collections.Generic.List & lt; SettingsTest.Data & gt; "... Don't forget that angle brackets are encoded in XML via entity& lt;and& gt;.
    5. Go back to Visual Studio, update the files (you can close and reopen the project), and recompile.
    6. Voilà, everything should magically work.

    Don't forget:

    1. Give your data class an attribute[Serializable].
    2. Declare it aspublic.
  • Answer # 4
    [Serializable]
    class Program
    {
        static void Main (string [] args)
        {
            Serialize ();
            Deserialize ();
        }
        static void Serialize ()
        {
            //create an object that will be serialized
            List &lt;
    string &gt;
     words= new List &lt;
    string &gt;
    ();
            words.Add ("world");
            words.Add ("door");
            words.Add ("ball");
            //open a stream for writing to a file
            FileStream fs= new FileStream ("file.s", FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
            BinaryFormatter bf= new BinaryFormatter ();
            //serialization
            bf.Serialize (fs, words);
            fs.Close ();
        }
        static void Deserialize ()
        {
            List &lt;
    string &gt;
     words;
            FileStream fs= new FileStream ("file.s", FileMode.Open, FileAccess.Read, FileShare.Read);
            BinaryFormatter bf= new BinaryFormatter ();
            words= (List &lt;
    string &gt;
    ) bf.Deserialize (fs);
            fs.Close ();
            foreach (string w in words)
            {
                Console.WriteLine (w);
            }
        }
    }
    

    Taken from here

    Thank. I also think about it. But the difficulty is that I would like to serialize several sheets of different classes compactly, into one file. I'm thinking of going further towards XML serialization.

    Анна Киселёва2021-03-05 09:57:28