XML Probleme beim Deserialisieren



  • Nun ich habe letztens in meinen Programm etwas mit Codeoptimierung begonnen ... jetzt werden aber nicht mehr alle Informationen beim Deserialisieren meiner XML geparst. Ich weiß auch zu 100% woran es liegt aber habe keine Ahnung wie ich es denn beheben sollte 😕

    namespace LangConf.Classes
    {
        public enum MESSAGE_CODE
        {
            ERR_INIT_D3D = 0,
            ERR_TEST
        }
    
        public class MessagePool<T>
        {
            protected virtual ArrayList m_messages { get; set; }
    
            protected MessagePool()
            {
                m_messages = new ArrayList();
            }
    
            public T[] Messages
            {
                get
                {
                    T[] msg = new T[m_messages.Count];
                    m_messages.CopyTo(msg);
                    return msg;
                }
                set
                {
                    if (value != null)
                    {
                        m_messages.Clear();
                        T[] msgList = (T[])value;
    
                        foreach (T msg in msgList)
                            AddMessage(msg);
                    }
                }
            }
    
            public void AddMessage(T newMessage)
            {
                if (newMessage != null)
                    m_messages.Add(newMessage);
            }
    
            public T GetMessage(int messageId)
            {
                if (messageId > m_messages.Count || messageId < 0)
                    return (T)Convert.ChangeType(null, typeof(T));
    
                return (T)m_messages[messageId - 1];
            }
    
            public bool MessageExists(int messageId)
            {
                return GetMessage(messageId) != null;
            }
    
        }
    
        [XmlRoot("Localisations")]
        public class LocalisationManager : MessagePool<XMLTranslation>
        {
            #region Singleton
            // Creating a single static instance of the class
            // this is not thread safe, will be added later
            private static volatile LocalisationManager m_singleton;
            private static object baseProc = new Object();
            // Retrieve or Set the static Instance
            public static LocalisationManager Instance
            {
                get
                {
                    if (m_singleton == null)
                    {
                        //lock Thread for other processes and start loading
                        lock (baseProc)
                            m_singleton = LocalisationManager.LoadLocaliations();
                    }
    
                    return m_singleton;
                }
                set { m_singleton = value; }
            }
            #endregion
    
            [XmlElement("Message")]
            public XMLTranslation[] Messages;
    
            public static LocalisationManager LoadLocaliations()
            {
                LocalisationManager newManager  = new LocalisationManager();
                XmlSerializer xmlserial         = new XmlSerializer(typeof(LocalisationManager));
                TextReader txtreader            = new StreamReader(System.Windows.Forms.Application.StartupPath + "\\config\\Localisation.xml");
                newManager                      = (LocalisationManager)xmlserial.Deserialize(txtreader);
                txtreader.Close();
                return newManager;
            }
    
            public void SaveRules()
            {
                XmlTextWriter txtWriter = new XmlTextWriter(System.Windows.Forms.Application.StartupPath + "\\config\\Localisation.xml", Encoding.UTF8);
                txtWriter.Formatting = Formatting.Indented;
    
                txtWriter.WriteStartDocument();
                txtWriter.WriteStartElement("Localisations");
                txtWriter.WriteAttributeString("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
                txtWriter.WriteAttributeString("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
    
                foreach (XMLTranslation msg in m_messages)
                {
                    txtWriter.WriteStartElement("Message");
                    txtWriter.WriteAttributeString("Name", msg.Name);
                    {
                        XMLMessage[] transList = msg.Messages;
    
                        foreach (XMLMessage trans in transList)
                        {
                            txtWriter.WriteStartElement("Translate");
                            txtWriter.WriteAttributeString("Lang", Convert.ToString(trans.Language));
                            txtWriter.WriteString(Convert.ToString(trans.Message));
                            txtWriter.WriteEndElement();
                        }
                    }
                    txtWriter.WriteEndElement();
                }
    
                txtWriter.WriteEndElement();
                txtWriter.WriteEndDocument();
                txtWriter.Close();
            }
        }
    
        public class XMLTranslation : MessagePool<XMLMessage>
        {
            private int                 m_id;
    
            [XmlAttribute("Name")]
            public string Name;
            [XmlElement("Translate")]
            protected override ArrayList m_messages {get; set;}
    
            public int ID
            {
                get { return m_id; }
                set { m_id = (int)value; }
            }
        }
    
        public class XMLMessage
        {
            [XmlAttribute(DataType = "string", AttributeName = "Lang")]
            public string Language;
            [XmlText()]
            public string Message;
    
            public XMLMessage() { }
        }
    }
    

    der Fehler liegt bei der Vererbten Variable

    protected virtual ArrayList m_messages { get; set; }
    

    Diese bleibt beim Deserialisieren immer unbeschrieben. Ich habe da definitiv ein kleines Logik verständnis Problem ... Es muss definitiv funktionieren irgendwie aber wie 😕 Fakt ist in der Basisklasse also das Generic brauche ich die Variable m_messages und in der Childklasse muss ich sie ja neu Deklarieren da der Deserialisierer sie sonst nicht anhand des Tags auflöst.
    Wer hat eine Idee?

    Vielen lieben Dank



  • Bitte kein m_... als Bezeichner.

    Sonst Custom Deserialiserer.

    Aber kannst ud nicht so was machen wie

    protected override ArrayList m_messages {get { return base.m_messages; } set { base.m_messages = value;}
    

    Standardeigenschaften (also mit get;set; ) erstellen eine neue Instanzvariable und da die Eigenschaft überschrieben wird, kriegt die Vaterklasse auch nichts davon mit.

    (Ungetestet / erraten)

    Edit: ich schaue mir gerade den Rest an:

    • Anstelle von MESSAGE_CODE Exceptions in Betracht ziehen.
    • Warum ArrayList und nichts generisches List<T> ?
    • Mache lieber MessagePool<T> : Iterable<T>, wenn du nicht alle Elemente auf einmal brauchst und du die nur in einer foreach -Schleifte einzelnd durchgest.

    dann brauchst du auch das Kopieren nicht.
    Und die Typüberprüfungen ebensowenig.

    Wenn du schonmal dabei bist, kannst du auch einige Methoden von ICollection implementieren und bei den anderen (Remove z.B.:) eine Excpetion werfwen)

    • Das Wikipedia: Double-checked locking ist nicht sauber implementiert.
    • Warum verwendest du XmlSerializer zum deserialiseren, aber XmlTextWriter zum erzeugen von XML?
    • XmlTextWriter txtWriter mit using verwenden.
    • Warum erfindest du das Rad mit der Lokalisierung neu und nimmst nicht, das was .Net schon zur Verfügung stellt?

    Sieh' diese Punkte aber bitte nicht als (destruktive) Kritik. Ich kenne dein Programm nicht, deswegen kann es sein, dass wegen deinen Rahmbedingungen Punkte nicht zutreffen.

    MfG
    Rhombicosidodecahedron



  • Keine m_ Bezeichner? ^^ Hat sich bei mir aber über Jahre so eingebürgert meine privaten Klassenvariablen so zu bezeichnen. Da sehe ich automatisch worauf ich zugreifen kann und worauf nicht ...

    Ja Costum Deserialisierer wäre eine Option aber ich muss doch nicht andauernd das Rad neu erfinden oder?

    protected override ArrayList m_messages {get { return base.m_messages; } set { base.m_messages = value;}
    

    Funktioniert leider nicht, er liest immer noch nichts herraus, das Array bleibt leer.

    Nein danke für Kritik bin ich immer offen, bin ja am optimieren aber bevor ich die nächsten Baustellen aufmache erstmal diese wieder fertigstellen 🙂

    Punkt 1 Exceptions sind nicht in Betracht zu ziehen da die XML einfach nur eine Art Languagefile ist ... deswegen MESSAGE_CODE damit ich irgendwie intern auf die einzelnen Strings zugreifen kann ohne mit Zahlen um mich zu werfen

    Punkt 2 Naja warum keine Ahnung mir war damals einfach danach ArrayList zu verwenden statt list Container ... aber das sollte kaum tragisch sein da ich ja definitiv immer weiß welche Message ich abrufe. Ich muss ja nichts suchen

    Punkt 3 lieber MessagePool<T> : Iterable<T>, klingt gut ja das werde ich bestimmt auch noch tun. Wie gesagt bin auf Optimierungstour und das macht einiges hübscher.

    Punkt 4 Das Singleton kommt ohnehin weg, ist nicht threadsafe da ist schon eine alternative am laufen.

    Punkt 5 Nun weil der XmlTextWriter meine Formatierung nicht zerstört 🙂

    Punkt 6 Naja alias kann man haben, man muss aber nicht ... besonders wenn ich nur 2 mal in den Scope agiere.

    Punkt 7 nein ich erfinde das Rad nicht neu denke ich


  • Administrator

    FoxDie schrieb:

    Keine m_ Bezeichner? ^^ Hat sich bei mir aber über Jahre so eingebürgert meine privaten Klassenvariablen so zu bezeichnen. Da sehe ich automatisch worauf ich zugreifen kann und worauf nicht ...

    Wenn du es nur für private Variablen verwendest, ist es ok. Mache ich auch 😉
    Aber du verwendest es auch für Properties und sogar für protected Properties. Das halte ich auch für weniger klug. In C# gibt es einige Standards für öffentliche Schnittstellen. Es ist sinnvoll diese einzuhalten. Und protected ist so gut wie öffentlich.

    Zu deiner Klasse ... ist nur schwer auf Anhieb hier sagen zu können, was falsch läuft. Habe ehrlich gesagt auch nicht all zu grosse Lust, mich jetzt da reinzuknien. Aber doch, du erfindest das Rad neu. Für Lokalisation und Internationalisierungen gibt es schon mehrere Bibliotheken. Es gibt sogar fertige Lösung vom .Net Framework selbst.

    Grüssli



  • Das m_message ist ja erst zur property verkommen nachdem ich virtual eingefügt habe, geht ja bei variablen nicht anders. und nein ich verwende es nicht für öffentliche variablen und protected ist nicht öffentlich ... es ist ja gewünscht das abgeleitete Klassen darauf Zugriff haben.

    Fertige Lösungen kenne ich nicht und ehrlich gesagt habe ich auch nicht danach gesucht, sowas ist ja eigentlich recht fix geschrieben. Wo findet man die .net librarys denn?



  • FoxDie schrieb:

    Fertige Lösungen kenne ich nicht und ehrlich gesagt habe ich auch nicht danach gesucht, sowas ist ja eigentlich recht fix geschrieben. Wo findet man die .net librarys denn?

    u.a. http://www.codeproject.com/Articles/59193/Localizing-a-Windows-Application-with-Satellite-As



  • Heureka ich hab es ... hatte heute morgen einen Geistesblitz!

    public abstract class MessagePool<T>
        {
            [XmlIgnoreAttribute]
            public virtual ArrayList m_messages { get; set; }
    

    Der Deserialisierer scheint keine Überschriebenen Felder interpretieren zu können, ihn muss man das explizit mit XmlIgnoreAttribute nochmal verdeutlichen das dieses Feld Ignoriert werden soll 😉

    Manchmal tut es auch eine Runde schlaf 😋

    Danke euch für die Ratschläge


Anmelden zum Antworten