Autor |
Beitrag |
schlumsch
      
Beiträge: 122
alles Win :)
Delphi 2005 Prof, Delphi 2007
|
Verfasst: Di 20.04.10 15:08
Hallo Gemeinde,
ich bin absolut neu in C# und stehe vor dem folgenden Problem:
Ich habe ein Textfile in welchem Zeilenweise Objekte mit ihren Attributen stehen. Das Format kann ich selber bestimmen, derzeit siehht es ungefähr so aus:
Zeit1|Zeit2|Objektname1|attributname1:attributtyp1|attributname2:attributty
p2|......
Zeit1|Zeit2|Objektname2|attributname1:attributtyp1|attributname2:attributty
p2|......
Zeit1|Zeit2|Objektname3|attributname1:attributtyp1|attributname2:attributty
p2|......
.
.
.
Nun bekomme ich ein Logfile und überprüfe wo dieses dem oben definierten Format entspricht, genauer: Wenn der Objektname einem Eintrag in Zeile x Position 3 meines oben geposteten Textfiles entspricht dann prüfe ich ob Anzahl und Typ der folgenden Attribute stimmen.
Soweit alles machbar denke ich, nun möchte ich allerdings nach der Prüfung gerne aus jeder Zeile meines Logfiles ein Objekt mit dem an Stelle 3 definierten Typ erstellen. Hier liegt mein Problem: wie? *g*
Das Format meines Logfiles kann sich ändern. Daher möchte ich nur an einer Stelle mein intern benutztes Format anpassen müssen, dies wäre im o.g. Textfile. Ich möchte also nicht zusätzlich "per Hand" Klassen definieren und dann Objekte daraus erstellen.
So wie ich mir das vorstelle würde ich jede Zeile meines Textfiles nach "|" und danach nach ":" splitten und dann sagen wollen:
Neue Klasse, Attributname = String vor dem ":" mit Attributtyp nach dem ":" so lange bis kein "|" ...
Geht das?  Wenn ja wie?
_________________ icq 102779206
"God is real, unless declared integer..."
|
|
JüTho
      
Beiträge: 2021
Erhaltene Danke: 6
Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
|
Verfasst: Di 20.04.10 15:26
Soll ich jetzt meine Antwort und eine weitere hierher kopieren, oder wie stellst du dir das vor?
Außerdem hat deine Frage wenig mit IO zu tun (bloß weil du die Informationen aus einer Textdatei holen willst), sondern viel, viel mehr mit dem Finden und Erstellen von Objekten nach dem Klassennamen.
Jürgen
|
|
danielf
      
Beiträge: 1012
Erhaltene Danke: 24
Windows XP
C#, Visual Studio
|
Verfasst: Di 20.04.10 15:27
Hallo,
ja das geht. Das nennt sich in .NET Reflection. Interessant könnte für dich die Klasse Activator sein. Dort kannst du unter anderem CreateInstance verwenden um mit dem Namen eines Typ ein Objekt zu erstellen. Den Typ bekommst du wiederum mit Assembly.GetExecutingAssembly().GetType("blub") bekommen.
Properties kannst du über <type>.GetProperty("name").SetValue(<dein erstelltes objekt>, <value>, null);
Aber ich denke mit dem Stichwort Reflection kommst du eh weiter (da gibts viel im Netz). Bei konkreten Problemen kannst dich ja nochmal hier im Thread melden.
.. öhm.. beim zehnten mal durchlesen denke ich das du doch was anders suchst...
Du hast die Klassen nicht, sondern willst diese erstellen?
Warum erstellst du nicht eine Klasse die einfach eine Liste von Attributen mit (Name, Type und Wert hat) und packst alles da rein?
Oder wie willst du es später wiederverwenden?
Ich bin verwirrt
Bitte um weitere Aufklärung.
Gruß
|
|
schlumsch 
      
Beiträge: 122
alles Win :)
Delphi 2005 Prof, Delphi 2007
|
Verfasst: Di 20.04.10 15:49
@JüTho: Also irgendwie fühl ich mich ein wenig veräppelt, um mal die Kraftausdrücke bei Seite zu lassen. Ich erwarte überhaupt nicht das du mir antwortest und finde die Crassposting-Regelung ziemlich blöd. Ist nun mal so das nicht alle Leute nur in einem Forum angemeldet sind und wenn man schnell eine Antwort benötigt est es schon hilfreich in mehreren Foren nachzufragen. Es ist ja absolut ausreichend wenn der Helfende in einem Forum hilft ... klingt blöd aber was solls...
Des weiteren habe ich ie Forne hier durchgeschaut und da ich das Forum "Finden und Erstellen von Objekten nach dem Klassennamen" nicht gefunden habe bin ich hier gelandet, bitte entschuldige!
-------------
So, nun wieder zum Thema: thx @ danielf. Ich habe mittlerweile auch schon von Activator gehört und werde das versuchen, insofern ich die Rahmenstruktur für mein Programm fertig habe. Ich melde mich wenns hakt
--- Moderiert von Kha: Beiträge zusammengefügt ---
Ha, und ich sollte erstmal Beiträge ganz lesen bevor ich antworte
Was ich habe ist ein Logfile in einem bestimmten Format, welches sich ändern kann...weiter erst einmal nichts.
Dabei ist jede Zeile ein abgeschliossener Datensatz, das Attribut 3 bestimmt den Typ, unterschiedliche Typen haben unterschiedliche (auch anzahl) weiterer Attribute.
Nun habe ich mir gedacht dass ich mir ein Textfile mit der Formatdef. erstelle, welches ich ggf. abändern kann. Klar ich in für jedes Objekt eine Klasse anlegen und dort alles hineinpacken , würde allerdings bedeutes dass ich bei jeder Formatänderung nicht nur meine FTextfile sondern eben auch jede Klasse abändern müsste...
_________________ icq 102779206
"God is real, unless declared integer..."
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Di 20.04.10 16:16
schlumsch hat folgendes geschrieben : | Ist nun mal so das nicht alle Leute nur in einem Forum angemeldet sind und wenn man schnell eine Antwort benötigt est es schon hilfreich in mehreren Foren nachzufragen. |
Und wenn verschiedene Personen in den verschiedenen Foren die gleiche Lösung erarbeiten, ohne voneinander zu wissen, ist das ja nicht dein Problem, stimmt  ...
schlumsch hat folgendes geschrieben : | Das Format meines Logfiles kann sich ändern. Daher möchte ich nur an einer Stelle mein intern benutztes Format anpassen müssen, dies wäre im o.g. Textfile. Ich möchte also nicht zusätzlich "per Hand" Klassen definieren und dann Objekte daraus erstellen. |
Dann gibt es nur zwei Möglichkeiten: Entweder du verzichtest auf die Textdatei und speicherst die Informationen stattdessen wie von Daniel vorgeschlagen in Attributen direkt in der Klasse oder du lässt aus der Textdatei automatisch Text generieren - mit T4 sollte das relativ leicht möglich sein.
Beide Verfahren fallen aber wahrscheinlich nicht gerade unter die Kategorie "anfängerfreundlich"  .
_________________ >λ=
|
|
schlumsch 
      
Beiträge: 122
alles Win :)
Delphi 2005 Prof, Delphi 2007
|
Verfasst: Di 20.04.10 16:44
Okay, ja nach Anfängerfreundlich klingt das wirklich nicht. Um mich da mal nicht in Tutorials zu verrennen denke ich wird es (zumindest im ersten Schritt) besser sein Klassen zu definieren. Danach werd ich mir mal Reflection zu Gemüte führen
_________________ icq 102779206
"God is real, unless declared integer..."
|
|
schlumsch 
      
Beiträge: 122
alles Win :)
Delphi 2005 Prof, Delphi 2007
|
Verfasst: Mi 21.04.10 15:06
Ja .. *meld*
Also ich versuche mich ein wenig in Reflektion einzuarbeiten und komme nicht wirklich weiter. Alle beispiele die ich bis jetzt gesehen habe drehen sich um die Auflistung von Feldern & methoden von Assemblys. Wenn ich das richtig verstehe ist eine Assembly zB ein Programm, sprich exe oder dll. Das bringt mir allerdings nicht allzuviel. Ich müsste quasi aus meinem Textfile mit den Objektdefinitionen jeweils eine Zeile auslesen und dann zur Laufzeit eine Klasse daraus generieren und dann beliebig instanziieren.
Der Klassenname müsste der jeweils 3te Eintrag in meinem Textfile sein, die Felder und Feldtypen werden durch die verbleibenden Einträge dieser Zeile definiert.
Eventuell kann mir da jemand einen Tip geben wo ich mich da schlau machen kann, derzeit verrenne ich mich in allen möglichen Tutorials
thx a lot
_________________ icq 102779206
"God is real, unless declared integer..."
|
|
danielf
      
Beiträge: 1012
Erhaltene Danke: 24
Windows XP
C#, Visual Studio
|
Verfasst: Mi 21.04.10 15:33
Was bringt es den dir eine Klases zur Laufzeit zu generieren? Was willst du damit erreichen?
Ich hab die Frage schon mal gestellt... und finde es dreist wie du hier reagierst. Das führt nur dazu das dir niemand mehr antwortet - egal in welchem Forum.
|
|
schlumsch 
      
Beiträge: 122
alles Win :)
Delphi 2005 Prof, Delphi 2007
|
Verfasst: Mi 21.04.10 16:03
Moment .. wieso denn dreist? Ich dachte ich hätte auf die Frage geantwortet, sorry wenn dem nicht so ist.
Mein Hauptproblem ist im Endeffekt das ich mit einem Logfile umgehen muss, dessen Format sich unter Umständen öfters ändert. Bei einer derartigen Änderung soll nicht jedes Mal mein ganzes Programm umgeschrieben werden. Deswegen ist mein derzeitigerc Ansatz das ich mir eine Definitions-datei anlege, dort zeilenweise hineinschreibe welches Feld von welchem Typ ein bestimmtes Objekt hat.
Bsp:
25.01.2010|26.01.2010|meinAuto|Farbe:String|Marke:String|......
Wenn ich nun in meinem Programm "selber" eine Klasse meinAuto anlege und dort die Felder als String definiere, so muss ich immer wenn ein anderes Logfileformat vorliegt auch die Klasse ändern.
25.01.2010|26.01.2010|meinAuto|Farbe:String|Marke:String|Länge:String|.... würde bedeuten ich muss die Klasse in meinem Programm ebenfalls "selbst" erweitern.
Nun dachte ich es wäre doch sicher möglich "einfach" (  ) die Klasse meinAuto nach dem Lesen des Definitionsfiles zu erstellen, der Klasse die im Definitionsfile hinterlegten Felder mit Feldtypen zu geben.
Danach könnte ich dann mein logfile einlesen, bei jedem "meinAuto" ein neues Objekt meiner eben angelegten Klasse instanziieren und meine Verarbeitungen starten.
Vorteil ist nun, dass ich nur das Definitionsfile anpassen muss sobald sich der log ändert.
_________________ icq 102779206
"God is real, unless declared integer..."
|
|
danielf
      
Beiträge: 1012
Erhaltene Danke: 24
Windows XP
C#, Visual Studio
|
Verfasst: Mi 21.04.10 16:29
Dreist hinsichtlich des crosspoints und dem damit nicht verbundenen Reuegefühl. Sowie die Tatsache, damit du dich nicht mit unseren Antworten befasst, sondern unbeeindruckt Fragen auf bereits gelöste Aspekte stellst.
Also ich versuche es nochmal.
Du musst doch so oder so deinen Code anpassen, wenn sich die Attribute deiner Klasse ändern. Abgesehen davon, ob du das nun manuell oder mithilfe eines Programm machst. Bsp:
Deine Klasse Auto:
C#-Quelltext 1: 2: 3: 4: 5:
| class Auto { public string Farbe { get; set; } public string Marke { get; set; } } |
Wenn nun die Klasse um das Attribut Länge erweitert wird, würde ein Code-Generator die Eigenschaft Länge vom Typ (dein Beispiel) string hinzu fügen. Den restlichen Code (wo du die Länge verwenden willst) musst du nun aber alles selber anpassen. Weil die Änderung der Klassenstruktur hat keinerlei Auswirkung auf deinen restlichen Code. Dort müsstest du bei jedem Zugriff überall das Auslesen/Setzen der Eigenschaft Länge per Hand nachziehen!!
Deshalb haben wir dir geraten einen generischen Typ zu machen, der wie deine Definitionsdatei/Logdatei/beliebige Quelle agiert und dementsprechend flexibel ist.
Das erreichst du eben, wenn du eine Klasse machst, die eine Liste von Attributen hat... wie in deiner Quelle.
Eine spezifische Klasse würde dir eh nichts nützen.
Comprende?
|
|
schlumsch 
      
Beiträge: 122
alles Win :)
Delphi 2005 Prof, Delphi 2007
|
Verfasst: Mi 21.04.10 17:23
Okay, zum Thema crosspoints hatte ich meine Auffassung geschildert und habe eure Argumentation keinesfalls ignoriert. Bislang habe ich es so gehalten das ich bei Antworten in einem Forum eventuelle Lösungsvorschläge eines anderen Forums mit eingebunden habe, sorry.
Zu der von dir erwähnten erforderlichen Codeanpassung: Ich muss lediglich die Daten aus dem Logfile überprüfen und danach in ein xml schreiben. Neue Felder werden also "nicht wirklich" verarbeitet, sondern müssen nur abgespeichert werden.
Soweit ich weiss kann das XML auf einer bestehenden Datenstruktur einfach via XmlSerializer erstellt werden.
Mit den Vorschlägen zur Lösung habe ich mich auch beschäftigt und ganz einfach Probleme mit der Umsetzung, wie gesagt ich habe sogesehen noch keine Zeile C# programmiert bevor ich dieses Projekt hier angehen durfte. (Ich habe so einige Beispiele zu Reflektion ausgetestet, ein wenig hat es mir auch geholfen)
Aber mal zurück zu der von dir angesprochenen Liste von Attributen:
Zitat: |
Deshalb haben wir dir geraten einen generischen Typ zu machen, der wie deine Definitionsdatei/Logdatei/beliebige Quelle agiert und dementsprechend flexibel ist.
Das erreichst du eben, wenn du eine Klasse machst, die eine Liste von Attributen hat... wie in deiner Quelle.
|
Sorry, leider verstehe ich das nicht so ganz und steh hier auf dem Schlauch.
Wie sähe die von dir angesprochene Liste von Attributen aus?
_________________ icq 102779206
"God is real, unless declared integer..."
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Mi 21.04.10 17:35
schlumsch hat folgendes geschrieben : | Neue Felder werden also "nicht wirklich" verarbeitet, sondern müssen nur abgespeichert werden. |
Dumm gefragt: Wofür dann überhaupt eine typisierte Container-Klasse? Würde es nicht genügen, wenn man über meinAuto["Farbe"] zugreifen würde?
Ansonsten ist mir nicht mehr klar, welchen der drei Wege du nun bestreiten willst - die Definitionsdatei fallen lassen und stattdessen in Attribute kodieren?
_________________ >λ=
|
|
norman2306
      
Beiträge: 222
Erhaltene Danke: 16
Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
|
Verfasst: Mi 21.04.10 18:40
So eine Spielerei mit dynamisch erstellten Typen habe ich mal gemacht, obwohl ich bezweifle, dass das, was du damit machen möchtest wirklich den Aufwand wert ist. Ich klemme dir trotzdem mal den Code ran. Er wandelt einen Dictionary<string,object> in einen dynamischen Typen um, wobei den Feldern/Properties immer der Typ zugewiesen wird, den der Wert des objects gerade hat. Ich würde dir aber trotzdem eher empfehlen, die Hinweise von Kah und Daniel zu beachten.
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: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242:
| public static object ConvertToDynType(Dictionary<string, object> ClassDefinition, string name, bool ConvertSubs) { Dictionary<string, object> ClassDef_tmp = new Dictionary<string, object>(ClassDefinition);
AssemblyName aName = new AssemblyName(name);
AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly( aName, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, "VDynLib" + ".dll"); TypeBuilder tb = mb.DefineType( name, TypeAttributes.Public);
FieldBuilder[] Fields = new FieldBuilder[ClassDef_tmp.Keys.Count];
Type[] parameterTypes = new Type[Fields.Count()];
if (ConvertSubs) for (int j = 0; j < ClassDef_tmp.Count; j++) { if (ClassDef_tmp.Values.ToArray()[j] != null && ClassDef_tmp.Values.ToArray()[j].GetType() == typeof(Dictionary<string, object>)) { string sub_name = "Type" + ClassDef_tmp.Keys.ToArray()[j]; object subType = ConvertToDynType((Dictionary<string, object>)ClassDef_tmp.Values.ToArray()[j], sub_name); ClassDef_tmp[ClassDef_tmp.Keys.ToArray()[j]] = subType; } }
for (int i = 0; i < ClassDef_tmp.Count; i++) { Type T1 = typeof(object); if(ClassDef_tmp.Values.ToArray()[i] == null) T1 = typeof(object); else T1 = ClassDef_tmp.Values.ToArray()[i].GetType();
Type RefType = T1.FullName == tb.FullName ? typeof(object) : T1;
Fields[i] = tb.DefineField( "_" + ClassDef_tmp.Keys.ToArray()[i], RefType, FieldAttributes.Private);
if (ClassDef_tmp.Values.ToArray()[i] == null) parameterTypes[i] = typeof(object); else parameterTypes[i] = ClassDef_tmp.Values.ToArray()[i].GetType();
}
ConstructorBuilder ctor1 = tb.DefineConstructor( MethodAttributes.Public, CallingConventions.Standard, parameterTypes);
ILGenerator ctor1IL = ctor1.GetILGenerator();
ctor1IL.Emit(OpCodes.Ldarg_0);
ctor1IL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
for (int k = 0; k < Fields.Count(); k++) { ctor1IL.Emit(OpCodes.Ldarg_0); ctor1IL.Emit(OpCodes.Ldarg_S, k + 1); ctor1IL.Emit(OpCodes.Stfld, Fields[k]);
} ctor1IL.Emit(OpCodes.Ret);
for (int n = 0; n < ClassDef_tmp.Keys.Count; n++) { Type T1 = ClassDef_tmp.Values.ToArray()[n].GetType(); Type RefType = T1.FullName == tb.FullName ? typeof(object) : T1;
PropertyBuilder pbNumber = tb.DefineProperty( ClassDef_tmp.Keys.ToArray()[n], PropertyAttributes.HasDefault, RefType, null);
CustomAttributeBuilder CAB = new CustomAttributeBuilder( typeof(System.ComponentModel.CategoryAttribute).GetConstructor(new Type[1] { typeof(string) }), new object[1] { name.Replace("Type", "") }); pbNumber.SetCustomAttribute(CAB);
MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
MethodBuilder mbNumberGetAccessor = tb.DefineMethod( "get_Field", getSetAttr, RefType, Type.EmptyTypes);
ILGenerator numberGetIL = mbNumberGetAccessor.GetILGenerator();
numberGetIL.Emit(OpCodes.Ldarg_0); numberGetIL.Emit(OpCodes.Ldfld, Fields[n]); numberGetIL.Emit(OpCodes.Ret);
pbNumber.SetGetMethod(mbNumberGetAccessor);
MethodBuilder mbNumberSetAccessor = tb.DefineMethod( "set_Field", getSetAttr, null, new Type[] { RefType });
ILGenerator numberSetIL = mbNumberSetAccessor.GetILGenerator(); numberSetIL.Emit(OpCodes.Ldarg_0); numberSetIL.Emit(OpCodes.Ldarg_1); numberSetIL.Emit(OpCodes.Stfld, Fields[n]); numberSetIL.Emit(OpCodes.Ret);
pbNumber.SetSetMethod(mbNumberSetAccessor);
} CustomAttributeBuilder CAB1 = new CustomAttributeBuilder( typeof(TypeConverterAttribute).GetConstructor(new Type[1] { typeof(Type) }), new object[1] { typeof(VDTPropertyConverter) }); tb.SetCustomAttribute(CAB1);
CustomAttributeBuilder CAB1 = new CustomAttributeBuilder( typeof(SerializableAttribute).GetConstructor(new Type[1] { typeof(Type) }), new object[1] { typeof(SerializableAttribute) }); tb.SetCustomAttribute(CAB1);
Type t = tb.CreateType();
object[] args = new object[ClassDef_tmp.Count]; args = ClassDef_tmp.Values.ToArray();
object o2 = Activator.CreateInstance(t, args);
return o2; } |
|
|
schlumsch 
      
Beiträge: 122
alles Win :)
Delphi 2005 Prof, Delphi 2007
|
Verfasst: Mi 21.04.10 20:46
Ja - welchen Weg will ich bestreiten ... gute Frage. Zunächst habe ich noch immer ein Verständnisproblem zu dem
Vorschlag generischer Typ von danielf. Bei einem generischen Typ lege ich den genauen Typ, also ob String, int..., nicht fest, right? Ich denke mal zu Generics muss ich mich noch schlau machen, habe noch nicht damit gearbeitet. Hat da vielleicht jemand ein kurzes Beispiel oder einen guten Link?
Wie du an meinem "hin und her" hier im Thread merkst ist mir der genaue Lösungsweg mehr oder weniger egal, hauptsache das ganze ist am Ende einigermassen dynamisch. Wenn ich die oben genannten, mir derzeit noch fremden Generics aussen vor lasse würde ich auf deine Frage:
Zitat: |
...wenn man über meinAuto["Farbe"] zugreifen würde?
|
so antworten:
Nicht ganz, prinzipiell schon *g*, ich müsste über alle Attribute der Klasse iterieren können. Aus meinem Log-File kann ich ja den Names eines Attributes ermitteln (das was vor dem : steht).Den Namen der Klasse habe ich auch aus dem Log. Nun müsste ich meine definierte Klasse instanziieren und für jeden Logfile-Eintrag nach dem passenden Attribut in der Klasse suchen und dort den Wert zuweisen.
@norman2306: ich danke dir für deinen code.
Ich denke mal ich werde morgen sowohl das Thema Generics wie auch den Code mal genauer anschauen und danach endlich zu einer Entscheidung kommen, wie ich mein Problem löse. Jetzt ist erstmal Fussball
thx, bis morgen *g*
_________________ icq 102779206
"God is real, unless declared integer..."
|
|
schlumsch 
      
Beiträge: 122
alles Win :)
Delphi 2005 Prof, Delphi 2007
|
Verfasst: Do 22.04.10 14:18
Hallo noch einmal,
ich habe mich dann doch dafür entschieden das Def-File weg zu lassen und das ganze in Klassen zu packen.
So habe ich zB. eine Klasse
C#-Quelltext 1: 2: 3: 4: 5:
| class Auto { public int A; public string B; } |
und
C#-Quelltext 1: 2: 3: 4: 5:
| class Bahn { public bool C; public dictionary<string, int> D; } |
Nun kann ich natürlich Listen vom Typ Auto oder Bahn erzeugen, soweit klar.
Es gibt doch sicher auch die Möglichkeit das ganze in einer Struktur zu speichern,
untypisierte Liste fällt mir hier ein aber darüber meckert ja jeder
Oder bin ich da voll auf dem Holzweg?
_________________ icq 102779206
"God is real, unless declared integer..."
|
|
danielf
      
Beiträge: 1012
Erhaltene Danke: 24
Windows XP
C#, Visual Studio
|
Verfasst: Do 22.04.10 15:40
Hmm.. wohl eher Holzweg
Gegeben ist dein Loginput:
Zeit1|Zeit2|Objektname1|attributname1:attributtyp1|attributname2:attributty
p2|......
Zeit1|Zeit2|Objektname2|attributname1:attributtyp1|attributname2:attributty
Dynamisch sind jeweils die Attribute, die restlichen Eigenschaften dieser Zeile sind fix. Deshalb lässt sich daraus folgende Klasse ableiten:
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:
| class LogEntry { public const string Pattern = "Zeit1|Zeit2|Objektname1|attributname1:attributtyp1|attributname2:attributty";
public DateTime Zeit1 { get; private set; } public DateTime Zeit2 { get; private set; } public string Name { get; private set; } public Dictionary<string, string> Attribute ( get; private set; }
private LogEntry( { Attribute = new Dictionary<string, string>(); }
public LogEntry CreateLogEntry(string line) { LogEntry logEntry = new LogEntry(); string[] args = line.Split('|');
logEntry.Zeit1 = DateTime.Parse(args[0]); logEntry.Zeit2 = DateTime.Parse(args[1]); logEntry.Name = args[2];
for (int i=3; i < args.Length; i++) { string[] keyValue = args[i].Split(':');
Attribute.Add(keyValue[0], keyValue[1]); } } } |
Folgendermaßen würde die Verwendung aussehen:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| string[] lines = File.ReadAllLines("Application.log"); List<LogEntry> logEntries = new List<LogEntry>();
foreach(var line in lines) { if (IsRegex.Match(LogEntry.Pattern, line)) { logEntries.Add(LogEntry.CreateLogEntry(line)); } } |
So ungefährt 
|
|
schlumsch 
      
Beiträge: 122
alles Win :)
Delphi 2005 Prof, Delphi 2007
|
Verfasst: Do 22.04.10 16:42
Ich danke dir erstmal. Das ist soweit nachvollziehbar und passt wohl besser
Ich teste es und gebe Bescheid ... habe da mitbekommen das ich mich in dem
Thread anfangs wirklich etwas unklar ausgedrückt habe deswegen muss ich da
noch etwas anpassen - wie gesagt thx.
_________________ icq 102779206
"God is real, unless declared integer..."
|
|
schlumsch 
      
Beiträge: 122
alles Win :)
Delphi 2005 Prof, Delphi 2007
|
Verfasst: Fr 23.04.10 10:38
Hallo nochmal,
ich habe da ein, genauer gesagt 3, Probleme mit dem Code.
Ich habe deine Klasse Logentry erstellt und den Aufruf in meiner
Programmklasse in die Main[] gepostet.
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 Agls_New.Datenmodell; using System.Xml; using System.IO; using System.Xml.Serialization; using System.Text.RegularExpressions;
namespace Agls_New { class Program
{ static void Main(string[] args) {
string[] lines = File.ReadAllLines("Application.log"); List<LogEntry> logEntries = new List<LogEntry>();
foreach (var line in lines) { if (IsRegex.Match(LogEntry.Pattern, line)) { logEntries.Add(LogEntry.CreateLogEntry(line)); } } ... |
folgendes kommt dabei raus:
* Der Name "IsRegex" ist im aktuellen Kontext nicht vorhanden
* Für das nicht statische Feld, die Methode oder die Eigenschaft "LogEntry.CreateLogEntry(string)" ist ein Objektverweis erforderlich.
* LogEntry.CreateLogEntry(string)": Nicht alle Codepfade geben einen Wert zurück.
Kannst du mir da nochmal helfen?
_________________ icq 102779206
"God is real, unless declared integer..."
|
|
JüTho
      
Beiträge: 2021
Erhaltene Danke: 6
Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
|
Verfasst: Fr 23.04.10 11:50
Das sind alles Standard-Fehlermeldungen:
schlumsch hat folgendes geschrieben : | * Der Name "IsRegex" ist im aktuellen Kontext nicht vorhanden |
Du hättest durch einen Blick in die SDK-Doku/MSDN/Hilfe feststellen können, dass es keine Standardmethode ist. Wegen des Namens und der Argumente vermute ich, es handelt sich um eine statische Methode von LogEntry.
schlumsch hat folgendes geschrieben : | * Für das nicht statische Feld, die Methode oder die Eigenschaft "LogEntry.CreateLogEntry(string)" ist ein Objektverweis erforderlich. |
CreateLogEntry muss wohl als statisch deklariert werden. Diese Methode soll schließlich "aus dem Nichts" (nämlich nach dem String) ein Objekt vom Typ LogEntry erstellen.
schlumsch hat folgendes geschrieben : | * LogEntry.CreateLogEntry(string)": Nicht alle Codepfade geben einen Wert zurück. |
Es fehlt offensichtlich (!) die return-Anweisung für das erzeugte Element.
Daniel sollte den Code also nochmals überprüfen und ergänzen.
Gruß Jürgen
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Fr 23.04.10 11:56
@ schlumsch: Erwartest du überhaupt, dass in der Logdatei einzelne Zeilen sind, die nicht dem Format entsprechen? Wenn nicht, lass die IsRegex-Zeile einfach weg und fange ggf. lieber Exceptions aus CreateLogEntry ab.
Statt einer statischen Methode bietet sich hier auch an, CreateLogEntry einfach zu einem Konstruktor zu machen ( logEntry darin dann durch this ersetzen).
JüTho hat folgendes geschrieben : | Daniel sollte den Code also nochmals überprüfen und ergänzen. |
Och, schlumsch kann es gerne auch erst einmal selbst versuchen  .
_________________ >λ=
|
|
|