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, aberXmlTextWriter
zum erzeugen von XML? XmlTextWriter txtWriter
mitusing
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
- Anstelle von
-
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
-
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. Undprotected
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