Autor |
Beitrag |
Dr.Prof.Evil
Hält's aus hier
Beiträge: 9
|
Verfasst: Do 15.01.15 17:29
Vorweg, ich weiß dieses Thema gab es schon mehr als einmal, aber ich möchte hier ein wenig anders auf diese eingehen
Hallo erstmal,
ich brauche für mein Programm(e) eine Liste, die unterschiedliche Typen besitzt.
Ich weiß, mit einer einfachen Liste ist dies nicht möglich. Ich habe auch nach langem Belesen keine Möglichkeit gefunden.
Ich habe mich also selber mal rangesetzt.
Es ist sicherlich naiv zu glauben, dass ich eine Lösung finde, ohne diese schon einmal gelesen zu haben
Ich habe also eine Klasse erstellt.
C#-Quelltext 1: 2: 3: 4: 5:
| [Serializable] public class SpecialList {
} |
Diese Klasse, erbt von einer Liste die aus einer anderen Klasse besteht.
C#-Quelltext 1: 2: 3: 4: 5:
| [Serializable] public class SpecificType : Evil.Microsoft.BindableBase {
} |
"BindableBase" wissen sicherlich manche, was das ist.
Die Klasse SpecificType, braucht nun eine Variable, die den Typen unterbringt. Ich habe dann dieses Problem so gelöst.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39:
| [Serializable] public class SpecificType : Evil.Microsoft.BindableBase { public SpecificType () : base () { }
private Object type;
public Object Type { get { return this.type; } set { this.SetProperty ( ref this.type, value ); } }
public void SetType<Type> ( Type _type ) { this.Type = _type; }
} |
Die Andere Klasse sieht nun wie folgt aus.
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| [Serializable] public class SpecialList : List<SpecificType> { public SpecialList () : base () { } } |
Nun, teste ich das Ganze.
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| Mensch mensch = new Mensch ();
String[] fileNames = { "pipette.cur", "Kontakt.cs" };
SpecialList spec = new SpecialList ();
spec.Add ( new SpecificType () ); spec.Add ( new SpecificType () ); spec.Add ( new SpecificType () ); spec.Add ( new SpecificType () );
spec[ 0 ].SetType<String> ( "Hundekuchen" ); spec[ 1 ].SetType<Boolean> ( true ); spec[ 2 ].SetType<Mensch> ( mensch ); spec[ 3 ].SetType<String[]> ( fileNames );
Evil.FileManager.SaveAList<SpecificType> ( spec, "saves.xml", true ); |
Mensch ist eine einfache Klasse mit einem Property:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31:
| using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml.Serialization;
namespace PlayGrees { [Serializable] public class Mensch { public Mensch () : base () { name = "Tom"; }
public String name; public String Name { get { return this.name; } set { this.name = value; } } } } |
Evil.FileManager.SaveAList<SpecificType> ( spec, "saves.xml", true ); ist eine Methode aus einer von mir geschrieben Klasse:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| public static void SaveAList<ListType> ( List<ListType> source, String path, Boolean overwriteAccess, Boolean doCryp = false ) { Evil.Hilfsklassen.ListSave<ListType> listSave = new ListSave<ListType> ( source ); listSave.Save ( path, overwriteAccess, doCryp ); } |
Evil.Hilfsklassen.ListSave<ListType> listSave = new ListSave<ListType> ( source );
listSave.Save ( path, overwriteAccess, doCryp );
Kommt von:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104:
| using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;
namespace Evil.Hilfsklassen {
[Serializable] public class ListSave<ListType> : Evil.Microsoft.BindableBase { public ListSave () : base () { }
public ListSave(List<ListType> source) { this.ToSave = source; }
public ListSave(ListType[] sourceArray) { this.ToSave = new List<ListType> (); foreach ( ListType l in sourceArray ) this.ToSave.Add ( l ); }
private List<ListType> toSave; public List<ListType> ToSave { get { return this.toSave; } set { this.SetProperty ( ref this.toSave, value ); } }
public void Save( String path, Boolean overwriteAccess, Boolean doCryp = false) { try { if ( doCryp == true ) Evil.FileManager.EncryptAndSerializeObject<ListSave<ListType>> ( path, this, overwriteAccess ); else Evil.FileManager.SerializeObject<ListSave<ListType>> ( path, this, overwriteAccess ); } catch (Exception e) { Console.WriteLine ( "Exception in ListSave.Save(String, bool, bool)" ); Console.WriteLine ( e.Source ); Console.WriteLine ( e.Message ); } }
public static ListSave<ListType> Load( String path, Boolean didCryped = false) { try { if ( didCryped == true ) return Evil.FileManager.DecryptAndDeserializeObject<ListSave<ListType>> ( path ); else return Evil.FileManager.DeserializeObject<ListSave<ListType>> ( path ); } catch (Exception e) { Console.WriteLine ( "Exception in ListSave.Load(String, bool)" ); Console.WriteLine ( e.Source ); Console.WriteLine ( e.Message ); }
return null; } } } |
Dort drin befinden sich nun wieder Methoden, die aus einer anderen Klasse kommen:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55:
| public static MyObjectClass DecryptAndDeserializeObject<MyObjectClass> ( String path, byte[] key = null ) { DESCryptoServiceProvider _key = new DESCryptoServiceProvider ();
if(key != null) { _key.Key = key; _key.IV = key; }
if ( File.Exists ( path ) == true ) { using ( FileStream fStream = new FileStream ( path, FileMode.Open, FileAccess.Read ) ) { if ( key == null ) { using ( CryptoStream cStream = new CryptoStream ( fStream, _key.CreateDecryptor ( Encoding.ASCII.GetBytes ( "64BitPas" ), Encoding.ASCII.GetBytes ( "InitVector" ) ), CryptoStreamMode.Read ) ) { XmlSerializer s = new XmlSerializer ( typeof ( MyObjectClass ) ); return (MyObjectClass) s.Deserialize ( cStream ); } } else { using ( CryptoStream cStream = new CryptoStream ( fStream, _key.CreateDecryptor (), CryptoStreamMode.Read ) ) { XmlSerializer s = new XmlSerializer ( typeof ( MyObjectClass ) ); try { return (MyObjectClass) s.Deserialize ( cStream ); } catch (Exception e) { Console.WriteLine ( e.Message ); } } } } }
return default ( MyObjectClass ); } |
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45:
| ublic static void EncryptAndSerializeObject<MyObjectClass> ( String path, MyObjectClass obj, Boolean overwrite = false, byte[] key = null ) { DESCryptoServiceProvider _key = new DESCryptoServiceProvider ();
if(key != null) { _key.Key = key; _key.IV = key; }
if ( overwrite == true ) FileManager.DeleteFile ( path, true ); using ( FileStream fStream = new FileStream ( path, FileMode.Create, FileAccess.Write ) ) { if ( key == null ) { using ( CryptoStream cStream = new CryptoStream ( fStream, _key.CreateEncryptor ( Encoding.ASCII.GetBytes ( "64BitPas" ), Encoding.ASCII.GetBytes ( "InitVector" ) ), CryptoStreamMode.Write ) ) { XmlSerializer s = new XmlSerializer ( typeof ( MyObjectClass ) ); s.Serialize ( cStream, obj ); } } else { using ( CryptoStream cStream = new CryptoStream ( fStream, _key.CreateEncryptor (), CryptoStreamMode.Write ) ) { XmlSerializer s = new XmlSerializer ( typeof ( MyObjectClass ) ); s.Serialize ( cStream, obj ); } } } } |
Mein Problem ist nun, dass wenn ich einen String, Boolean oder Int32 speichere, funktionierts. Sobald ich aber ein Array oder Mensch speichern möchte, kommt ein Fehler:
"Beim Generieren des XML-Dokuments ist ein Fehler aufgetreten."
{System.InvalidOperationException: Der Typ PlayGrees.Mensch wurde nicht erwartet. Verwenden Sie das XmlInclude- oder das SoapInclude-Attribut, um Typen anzugeben, die nicht statisch sind.
bei System.Xml.Serialization.XmlSerializationWriter.WriteTypedPrimitive(String name, String ns, Object o, Boolean xsiType)
bei Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterListSave1.Write1_Object(String n, String ns, Object o, Boolean isNullable, Boolean needType)
bei Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterListSave1.Write3_SpecificType(String n, String ns, SpecificType o, Boolean isNullable, Boolean needType)
bei Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterListSave1.Write4_ListSaveOfSpecificType(String n, String ns, ListSave`1 o, Boolean isNullable, Boolean needType)
bei Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterListSave1.Write5_ListSaveOfSpecificType(Object o)}
Ich habe ehrlich gesagt keine Ahnung, was ich zu tun habe.
M.f.G.
Dr. Prof. Evil | Tom
Moderiert von Th69: Titel geändert: "Hilfe" entfernt
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Do 15.01.15 17:46
Der XmlSerialiser kann nur bekannte Typen serialisieren/deserialisieren. In deinem Serializer Code ist dem XmlSerializer NUR MyObjectClass bekannt.
Nur die kann er Serialisieren keine Ableitungen davon (ich spar mir gerade mal die ganzen Details des warum).
Wenn du Ableitungen von MyObjectClass serialisieren können willst mußt du die ALLE benennen (die müssen zur Compilezeit dem Serializer bekannt sein). Eine Möglichkeit, die auch die Exception benennt, ist alle Ableitungen von MyObjectClass die du serialisieren können möchtest an MyObjectClass bekannt zu machen in dem du eben der Klasse MyObjectClass ein XmlInclude Attribut verpasst und alle aufzählst.
C#-Quelltext 1: 2: 3: 4: 5:
| [XmlInclude(typeof(Mensch)), XmlInclude(typeof(Tier))] public MyObjectClass : WhatSoEverClass { ... } |
Edit: Es ist nett wenn man nicht immer alle Details erfragen muß und schon potentiell relevantes mitliefert was für die Beantwortung wichtig sein könnte. Man kann aber auch übertreiben
Edit2: Falls MyObjectClass ein generischer Platzhalter für einen konkreten Typ ist und gar keine eigene Klasse gilt oben gesagtes natürlich für die konkret benutzte Klasse. Und falls dem so ist würde es helfen für generische Platzhalter ein spezielles Naming zu verwenden. Es hat sich üblicherwese eingebürgert den Namen mit einem T zu präfixen. Wennn man sich daran hält funktionieren übrigens auch die Reflexe der hier anwesenden potentiellen Helfer besser 
|
|
Dr.Prof.Evil 
Hält's aus hier
Beiträge: 9
|
Verfasst: Fr 16.01.15 15:25
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Fr 16.01.15 16:19
Zitat: | Kann ich den XmlInclude auch im Aufruf erst erwähnen |
Du kannst das an der Methode bei der Methodendefinition erwähnen aber natürlich nicht bei der Methodenverwendung(Dieses Attribut ist eine Metainfo für den Serializer zur Compilezeit nicht zur Laufzeit.) An der Methode ist aber noch weniger sinnvoll als an der Klasse. Du kannst ja nicht mehr auf den Ändern des Typs T reagieren.
Zitat: | dass ich in .dll Projekt ja nicht angeben kann,welche Klassen alle er kennen muss, da die in diesem Projekt ja nie existieren werden. |
Alternativ kannst du dem XmlSerializer über den Konstruktor eine Array aller möglicherweise auftretenden Klassen mitgeben. Aber zum Zeitpunkt des Erzeugens des XmlSerialzers müssen die ALLE bekannt sein und du mußt die benennen können egal ob über ein Attribut oder diese Typ Liste.
|
|
Palladin007
      
Beiträge: 1282
Erhaltene Danke: 182
Windows 11 x64 Pro
C# (Visual Studio Preview)
|
Verfasst: Fr 16.01.15 17:18
Eine Option ist vielleicht, die verwendeten Typen auch zu speichern? Der vollständige Name des Typs reicht aus, dann kann .NET den Typ wieder finden, solange die verwendeten Assemblys weiterhin erreichbar sind.
Du müsstest dann allerdings vorher diese Liste als extra Datei daneben legen (ist am einfachsten), oder in die XML, allerdings müsstest du das dann vorher raus lesen, was sich aber mit LINQtoXML gut lösen lässt. Den Haupt-Aufwand der Deserialisierung übernimmt dann trotzdem der XmlSerializer.
Alternativ kannst du ganz LINQtoXML verwenden, flexibler geht nicht, allerdings musst du dann alles selber machen.
Oder du implementierst für jeden verwendeten Typ das IXmlSerializable-Interface und schreibst für jeden Listen-Inhalt noch zusätzlich den Typ dazu. Wenn du den verwendeten Typ hast, kannst du den dann nehmen und dort die ReadXml-Methode von IXmlSerializable aufrufen. Die macht dann genau das gleiche auch für die unbekannten Objekte, die in ihrem XML-Abschnitt vorhanden sind.
Oder du verwendest Soap, das ist nicht mehr so schön zu lesen wie XML, kann aber mit deiner Problemstellung umgehen, ohne dass du noch etwas dazu machen musst.
|
|
Dr.Prof.Evil 
Hält's aus hier
Beiträge: 9
|
Verfasst: Fr 16.01.15 19:53
Palladin007 hat folgendes geschrieben : | Eine Option ist vielleicht, die verwendeten Typen auch zu speichern? Der vollständige Name des Typs reicht aus, dann kann .NET den Typ wieder finden, solange die verwendeten Assemblys weiterhin erreichbar sind.
Du müsstest dann allerdings vorher diese Liste als extra Datei daneben legen (ist am einfachsten), oder in die XML, allerdings müsstest du das dann vorher raus lesen, was sich aber mit LINQtoXML gut lösen lässt. Den Haupt-Aufwand der Deserialisierung übernimmt dann trotzdem der XmlSerializer.
|
Ich habe schon begonnen an der Idee zu arbeiten. Habe nun 2 Methoden. Einmal die, die die Objekte alle einserialisiert. (kompliziertes Wort) Und einmal die, die die ausliest.
Erst einmal, was habe ich bis jetzt getan:
___________________________________________________________________________________________________________________________________________________________________________________________________________
Um wieder zu übertreiben, dafür aber wenig Fragen aufkommen:
Ich habe erstmal eine neue Klasse erstellt.
C#-Quelltext 1: 2: 3: 4: 5: 6:
| [Serializable] public partial class SpecialSerialize : Evil.Microsoft.BindableBase { } |
Diese klasse ist partial, weil sie über eine andere Klasse aufrufbar sein soll.
Nun habe ich wieder Properties erstellt. Dieses Mal eine Liste mit Objects (Meine Typen), und einmal eine Liste<String>, die später alle Namen von den Listen aller Klassen von den Typen in der
richtigen Reihenfolge beherbergt. ( Achtung, es besteht durch den komplizierten Satz hoffentlich keine Missverständnisgefahr)
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48:
| [Serializable] public partial class SpecialSerialize : Evil.Microsoft.BindableBase { public SpecialSerialize () : base () { this.Type = new List<Object> (); }
private List<Object> type; [XmlIgnore] private List<Object> Type { get { return this.type; } set { this.SetProperty ( ref this.type, value ); } }
private List<String> nameOfAllType; public List<String> NameOfAllTypes { get { return this.nameOfAllType; } set { this.SetProperty ( ref this.nameOfAllType, value ); } }
#region " Add und Get: AddType<T> | GetObject
public void AddType<T> ( T type ) { this.Type.Add ( type ); }
public Object GetObject ( Int32 _index ) { return this.Type[ _index ]; }
#endregion |
Zu beachten ist, dass die Liste mit Objekten ignoriert werden soll, vom Serializer.
___________________________________________________________________________________________________________________________________________
Nun kommen die möglicherweise komplizierten Methoden.
Bitte kein Gemecker an manchen Stellen.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73:
| public void Save ( String mainPath, Boolean overwriteAccess = false ) {
List<String> tempPaths = new List<String> (); for ( int i = 0 ; i < this.Type.Count ; i++ ) tempPaths.Add ( "tempSave" + i + ".xml" );
List<String> toWrite = new List<String> ();
if ( overwriteAccess == true ) { try { FileManager.DeleteFile ( mainPath, true ); } catch ( Exception e ) { Console.WriteLine ( e.Message ); } }
Int32 counter = 0; foreach ( String path in tempPaths ) { using ( FileStream stream = new FileStream ( path, FileMode.Create, FileAccess.Write ) ) { try { XmlSerializer s = new XmlSerializer ( this.Type[ counter ].GetType () ); s.Serialize ( stream, this.Type[ counter ] ); } catch ( Exception e ) { Console.WriteLine ( e.Message ); } }
String[] linesInFile = Evil.FileManager.ReadLinesInFile ( path ); foreach ( String s in linesInFile ) { toWrite.Add ( s ); } counter++; }
String[] toWriteAsArray = new String[ toWrite.Count ]; counter = 0; foreach ( String s in toWrite ) { toWriteAsArray[ counter ] = s; counter++; }
Evil.FileManager.WriteLinesInFile ( toWriteAsArray, mainPath, overwriteAccess );
this.NameOfAllTypes = new List<String> (); for ( int i = 0 ; i < this.Type.Count ; i++ ) this.NameOfAllTypes.Add ( this.Type[ i ].GetType ().Name );
Evil.FileManager.SerializeObject<SpecialSerialize> ( "_SpecialSerialize_NamesOfAllTypes.xml", this, true ); } |
Hier wird nun jeder Type serialisiert. Der Inhalt der Datein, wird erfolgreich zusammengeführt.
Zusätzlich, werden die Namen jeder Klassen jedes Types aufgelistet und ebenfalls über die eigene Klasse selbst, serialisiert.
________________________________________________________________________________________________________________________________________
Nun kommt das Laden.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79:
| public static SpecialSerialize Load ( String mainPath ) {
SpecialSerialize specialSerialize = Evil.FileManager.DeserializeObject<SpecialSerialize> ( "_SpecialSerialize_NamesOfAllTypes.xml" );
List<String> tempPaths = new List<String> (); for ( int i = 0 ; i < specialSerialize.NameOfAllTypes.Count ; i++ ) tempPaths.Add ( "tempSave" + i + ".xml" );
String[] tempLinesInFile = Evil.FileManager.ReadLinesInFile ( mainPath ); List<String> linesInFile = new List<String> (); Int32 counterFirstForEach = 0; foreach ( String className in specialSerialize.NameOfAllTypes ) { foreach ( String str in tempLinesInFile ) linesInFile.Add ( str ); List<String> toWriteInTemp = new List<String> ();
foreach ( String line in linesInFile ) { String toCheck = "</" + className + ">"; if ( line != toCheck ) toWriteInTemp.Add ( line ); if ( line == toCheck ) { toWriteInTemp.Add ( line ); break; } }
for ( int i = 0 ; i < toWriteInTemp.Count ; i++ ) linesInFile.Remove ( linesInFile[ 0 ] );
String[] toWriteAsArray = new String[ toWriteInTemp.Count ]; Int32 counter = 0; foreach ( String str in toWriteInTemp ) { toWriteAsArray[ counter ] = str; counter++; }
Evil.FileManager.WriteLinesInFile ( toWriteAsArray, tempPaths[ counterFirstForEach ], true );
counterFirstForEach++; }
foreach ( String path in tempPaths ) { if ( File.Exists ( path ) == true ) { using ( FileStream stream = new FileStream ( path, FileMode.Open, FileAccess.Read ) ) { XmlSerializer s = new XmlSerializer ( typeof ( Object ) ); specialSerialize.Type.Add ( s.Deserialize ( stream ) ); } } else {
} }
return specialSerialize; } |
Hier wird eine Menge getan. Genau genommen, alles andersherum. Ich teile die MainDatei und schreibe alles getrennt in mehrere Datein, die ich dann jeweils Typ für Typ in der richtigen Reihenfolge,
deserialisieren könnte doch:
Du sagtest, dass es reicht, den Namen des Typs zu wissen. Ich habe ja alle ausgelesen und besitze auch alle. Wie kann ich das nun verwenden?
M.f.G. Dr. Prof. Evil | Tom
P.S. Bei Fragen, die sich hier sicherlich nicht vermeiden lassen, einfach stellen. 
|
|
Palladin007
      
Beiträge: 1282
Erhaltene Danke: 182
Windows 11 x64 Pro
C# (Visual Studio Preview)
|
Verfasst: Fr 16.01.15 21:49
Versuch mal das.
Den Link habe ich aber innerhalb zwei Sekunden mit "c# get type of full name" gefunden, gleich der zweite Streffer
Allgemein würde ich dir noch empfehlen, deine Methoden etwas besser zu strukturieren und auch auf eine einzige Aufgabe zu reduzieren.
Es ist mir noch bei jeder Methode gelungen, sie in Teilaufgaben zu splitten, kombiniert mit einer geschickten Benennung der Methode und der Parameter, kann allein der Aufruf den ganzen Inhalt der Methode verraten und so den ganzen Code viel übersichtlicher machen.
Ich muss gestehen, dass ich mir den Code nicht angeschaut habe, ich beobachte das auch bei meinem eigenen Code, wenn ich Abneigung spüre, mir den Code einer Methode anzuschauen, ist sie definitiv zu lang bzw. zu unsortiert/unordentlich.
Was den ganzen Beitrag angeht:
Der Wunsch, keine Fragen offen zu lassen, ist zwar positiv und kann es durchaus einfacher machen, zu helfen, zu viel Text kann aber auch stark demotivieren, überhaupt zu helfen. Die Kunst ist wie so oft, den Mittelweg zu finden. Möglichst wenig schreiben, aber möglichst viele ungestellte Fragen beantworten und gleichzeitig das Problem möglichst genau beschreiben. Bei dir läuft ja alles auf eine Frage hinaus, der Rest darüber ist doch eigentlich gar nicht notwendig, oder?
Aber zurück zum Thema:
Ich habe ja oben einen Link geschickt, wie du ein Type-Objekt von dem Name des Typs erhältst. Wenn du den Namen von der FullName-Property erhältst, sollte das kein Problem darstellen.
Instanziieren kannst du den Typ mit der Activator-Klasse und einer der CreateInstance-Überladungen. Die Methoden rufen intern einen Konstruktor auf, welcher das ist, musst du ihr mit teilen, sonst sucht sie einen parameterlosen Konstruktor, der vielleicht nicht da ist.
Wenn die Klassen IXmlSerializable implementiert haben, dann kannst du dahin casten und dann die Methoden nutzen, wenn nicht, musst du die Eigenschaften selber schreiben, was dann schon aufwendiger wird.
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Fr 16.01.15 22:22
Mir ist das auch zuviel Code der vermutlich rein gar nix mit dem Problem zu tun hat was tatsächlich gelöst werden soll. Mich beschleicht sogar das Gefühl das da gar kein Problem existiert sondern du irgendwo falsch abgebogen bist und dich an irgendwas eigentlich unnötigem abarbeitest. Vielleicht drehen wir das Rad darum gerade nochmal zurück und du erzählst was das initiale Problem ist und wir versuchen nicht das Problem innerhalb Problemlösung zu beseitigen solange wir das eigentliche Problem nicht kennen.
Also was ist das Problem?
z.B.
- Persistieren eines Programmzustands?
- Transportieren von Daten?
Was sind dabei die Randbedingungen?
z.B.
- Datenformat der persistierten Daten
- Wie generisch muss das sein (aka zu welchem Zeitpunkt ist bekannt was für Typen serialisiert werden müssen)
- muss das auch wieder eingelesen werden können? und wenn ja von wem (dem eigenen Programm (versionsunabhängig) oder auch von anderen Programmen)
|
|
Dr.Prof.Evil 
Hält's aus hier
Beiträge: 9
|
Verfasst: Fr 16.01.15 23:02
Okay. Zurückspulen ist eine gute Idee.
Also: Ich habe mich an eine Klasse herangewagt, die eine Liste aus verschiedenen Typen beinhalteten soll. Gelöst habe ich das Problem, wie nach dem Absatz beschrieben.
Herausbekommen haben wir schon einmal, dass der Typ/die Typen für den XmlSerializer beim Serialisieren unbekannt ist/sind, da beim serialisieren als Type die Klasse mit der
Liste der unterschiedlichen Typen angegeben wird, und nicht jeder einzelne Typ in der Liste.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36:
| [Serializable] public class SpecificType : Evil.Microsoft.BindableBase { public SpecificType () : base () { }
private Object type;
public Object Type { get { return this.type; } set { this.SetProperty ( ref this.type, value ); } }
public void SetType<Type> ( Type _type ) { this.Type = _type; }
} |
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| [Serializable] public class SpecialList : List<SpecificType> { public SpecialList () : base () { } } |
Existieren, tut die Klasse/Klassen in einer .dll Datei. Das heißt, dass wir im .dll Projekt selber die zu serialisierenden Typen verlangen müssen.
Das selbe natürlich auch, fürs Auslesen. Dabei muss auch jeder Typ wieder in die Liste eingelesen werden.
Ich hatte nun einmal die Idee, alle Typen einzeln zu serialisieren, und den Inhalt aller Datein zusammen in eine zu stopfen.
Beim auslesen genau anders herum. Doch muss man dem XmlSerializer sagen, welchen Typ er deserialisieren soll, doch können wir ihm das im .dll Projekt selber nicht sagen.
M.f.G.
Dr. Prof. Evil | Tom
Moderiert von Th69: Vollzitat entfernt.
|
|
Palladin007
      
Beiträge: 1282
Erhaltene Danke: 182
Windows 11 x64 Pro
C# (Visual Studio Preview)
|
Verfasst: Fr 16.01.15 23:26
Ich glaube, du hast Ralf falsch verstanden
Er meint den Grund, warum du die Daten überhaupt serialisieren willst, was ist das Ziel und warum unbedingt XML? Was sind die Rahmenbedingungen, wäre ein anderer Weg vielleicht auch möglich oder besser?
|
|
|