C# 中的序列化异常

SerializationException in C#

我在 CSharp 中的代码中有以下异常:

The serializer doesnt take count the serialization of generic types: System.Collections.Generic.SortedSet`

这是我的有问题的代码(在 class FileStreamer 中):

 public static bool SoapSave(SortedSet<T> set, string filename)
        {
            FileStream stream = File.Create(filename);
            SoapFormatter formatter = new SoapFormatter();

            formatter.Serialize(stream, set);
            stream.Close();
            return true;
        }

下面是我在项目中使用的class:

主要class:

 class Program
    {
        public static void Main(string[] args)
        {
            GestAuthentification ga = new Authentification () ;

             try 
             {
                 ga.addUser("bob","123");
                 ga.removeUser("bob");
                 ga.removeUser("bob");
             } catch (UserUnknown e) {
                 Console.WriteLine(e.Login +" est inconnu du système! on ne peut le retirer.");
             } catch (UserExists e) {
                Console.WriteLine(e.Login +" est déjà dans le système! on ne peut le recréer.");
             }

             try 
             {
                ga.addUser("bob","123");
                ga.authentify("bob","123");
                ga.authentify("bob","456");
             } catch (WrongPassword e) {
                Console.WriteLine(e.Login+" s'est trompé de password !");
             } catch (UserExists e) {
                Console.WriteLine(e.Login +" est déjà dans le système! on ne peut le recréer.");
             } catch (UserUnknown e) {
                Console.WriteLine(e.Login +" est inconnu du système! on ne peut le retirer.");
             }

        //Until here it works
             try 
             {
                ga.save("users.txt");
                GestAuthentification gb = new Authentification();
                gb.load("users.txt");
                gb.authentify("bob","123");
                Console.WriteLine("Test sauvegarde/chargement réussi !");
             } catch (UserUnknown e) {
                Console.WriteLine(e.Login +" est n'est plus connu. Problème de sauvegarde/chargement.");
             } catch (WrongPassword e) {
                Console.WriteLine(e.Login+" s'est trompé de password !Problème de sauvegarde/chargement."); 
             } catch (IOException e) {
                Console.WriteLine(e);
            }
        }
        }

Authentification.cs

[Serializable]
    public class Authentification: GestAuthentification
    {
        private SortedSet<User> userset;

        public Authentification()
        {
            this.userset = new SortedSet<User>();
        }

        public void addUser(String login, String pass)
        {
            if (userset.Count() == 0)
            {
                User usr0 = new User(login, pass);
                userset.Add(usr0);
                Console.WriteLine(usr0._login + " a été ajoute");

                return;
            }
            else
            {

                foreach (User u in userset)
                {
                    if (u._login.Equals(login))
                    {
                        throw new UserExists(u);
                    }
                }
                User usr = new User(login, pass);
                userset.Add(usr);
                Console.WriteLine(usr._login + " a été ajoute");
            }
        }

        public void removeUser(String login)
        {
            foreach (User u in userset)
            {
                if (u._login.Equals(login))
                {
                    userset.Remove(u);
                    Console.WriteLine(u._login + " a été retiré.");
                    return;
                }
            }
            User usr = new User(login,"");
            throw new UserUnknown(usr);
        }

        public void authentify(String login, String Pass)
        {
            foreach (User u in userset)
            {
                if (u._login.Equals(login)&&u._password.Equals(Pass))
                {
                    Console.WriteLine(u._login + " a été authenthifié.");
                    return;
                }
                else if((u._login.Equals(login))&&(u._password.Equals(Pass)==false))
                {
                    throw new WrongPassword(u);
                }
            }
            User usr = new User(login, "");
            throw new UserUnknown(usr);
        }

        public void load(String path)
        {
            FileStreamer<User>.SoapLoad(path);
        }

        public void save(String path)
        {
            FileStreamer<User>.SoapSave(userset, path);
        }
    }

FileStreamer.cs

public class FileStreamer<T>
    {
        public static bool SoapSave(SortedSet<T> set, string filename)
        {
            FileStream stream = File.Create(filename);
            SoapFormatter formatter = new SoapFormatter();

            formatter.Serialize(stream, set);
            stream.Close();
            return true;
        }

        public static SortedSet<T> SoapLoad(string filename)
        {
            FileStream stream = File.OpenRead(filename);
            SoapFormatter formatter = new SoapFormatter();

            SortedSet<T> set = (SortedSet<T>)formatter.Deserialize(stream);
            stream.Close();
            return set;
        }
    }

User.cs

 public class User: IComparable<User>
    {
        private string login;

        private string password;

        public string _login
        {
            get{return login;}

            set {login=value;}
        }

        public string _password
        {
            get { return password; }
            set { password = value; }
        }

        public User(string l, string p)
        {
            login = l;

            password = p;
        }

        public int CompareTo(User u)
        {
            if(login.CompareTo(u._login)>0)
            {
                return 1;
            }
            else if(login.CompareTo(u._login)==0)
            {
                return 0;
            }
            else
            {
                return -1;
            }
        }
    }

那么我项目中序列化的问题在哪里,如何纠正?

谢谢。

您可能会在现代 .Net 上下文中使用 SoapFormatter 遇到许多问题。来自 docs:

Beginning with the .NET Framework 2.0, this class is obsolete. Use BinaryFormatter instead.

也就是说,如您所见,SoapFormatter 不支持泛型。但是,它确实支持 arrays,数组早在 .Net 1 就已存在。因此您可以将 SortedSet<T> 序列化为数组:

public class FileStreamer<T>
{
    static void SoapSave(SortedSet<T> set, Stream stream)
    {
        var formatter = new SoapFormatter();
        formatter.Serialize(stream, set.ToArray());
    }

    public static SortedSet<T> SoapLoad(Stream stream)
    {
        var formatter = new SoapFormatter();
        var array = (T [])formatter.Deserialize(stream);
        return new SortedSet<T>(array);
    }

    public static bool SoapSave(SortedSet<T> set, string filename)
    {
        using (var stream = File.Create(filename))
        {
            SoapSave(set, stream);
        }
        return true;
    }

    public static SortedSet<T> SoapLoad(string filename)
    {
        using (var stream = File.OpenRead(filename))
        {
            return SoapLoad(stream);
        }
    }
}

注意 SoapFormatter 还要求您将 User class 标记为 [Serializable]:

[Serializable]
public class User : IComparable<User>
{
    // Remainder of the class unchanged.
}