Strings als Referenz in eine List(Of String) packen

  • VB.NET
  • .NET (FX) 4.0

Es gibt 25 Antworten in diesem Thema. Der letzte Beitrag () ist von WhitePage.

    Strings als Referenz in eine List(Of String) packen

    Hallo,

    ich habe aus XML-Schema automatisch erstellte Klassen, die gleiche Propertys haben. Aktuell sind es 20 Objekte, jeder hat leider eine eigene Klasse (im Designer generiert), so dass ich sie nicht in eine List(Of) packen kann.
    Diese Klassen haben gleiche Propertys, z.B. visible as Boolean und value as String.
    Ich habe mir überlegt, dass ich die Propertys in eine List(Of Boolean) und List(Of String) packe, damit ich sie in der Schleife initialisieren kann und keinen meterlangen Code habe. Allerdings wird dabei nur ein Wert übergeben und keine Referenz, so dass die Propertys nicht gesetzt werden.

    Gibt es da eine Möglichkeit, die Propertys in einer Schleife zu setzen?

    Danke.
    Du kannst die generierten Klassen mit dem Partial-Konstrukt um weitere Funktionalität erweitern, auch um Interfaces.
    Wenn die Erweiterungen nicht serialisierbar gestaltet werden, sollte es zu keinen Konflikten kommen.

    Hofflich reicht der Hinweis, sonst musste nochmal ein kluges Buch nachlesen, bezüglich Polymorphie, und was man mit Interfaces so anstellen kann.
    Ja, ich weiß, wie es funktioniert, habe es auch schon überlegt. Allerdings dachte ich, es ist nie gut, im Designercode rumzupfuschen. Zumal fremder Code da häufig genug bei Aktualisierungen gelöscht wird (wenn man XML-Schema anpasst, dann wird die Designer-Datei neu erzeugt).
    D.h. ich darf dann jedes Mal neu schreiben, das Schema ist wirklich umfangreich, da ist einiges an Klassen...

    @EaranMaleasi
    Das schon eher, weil es nur um Code in meiner Klasse geht. Kannst du mir ein Beispiel geben?

    WhitePage schrieb:

    Ja, ich weiß, wie es funktioniert
    Offsichtlich nicht.
    Also den Interface-Kram vlt. aber Partial löst die Probleme, die du siehst.

    Reflection würde ich erst als allerletzte Notlösung betrachten, denn mit Reflection Werte zu setzen ist prinzipiell immer ein Hack, der die gewollte Strukturierung der Sprache umgeht.

    ErfinderDesRades schrieb:

    Also den Interface-Kram vlt. aber Partial löst die Probleme, die du siehst.


    Ach so, meinst du, dass ich die Deklarierung von implements IXML in meinem Code vornehmen kann? Aber die ganzen Propertys werden ja im Designer erstellt, müsste daneben nicht implements IXML.value usw stehen? Oder bei einer Basisklasse dann overrides?
    Auch wenn es Partial ist, trotzdem stehen die Definitionen und Deklarationen nun mal drin.

    @Rainman
    Das ist mir klar, nur leitet der Designer die nun mal leider nicht von einer Basisklasse ab. Sondern erstellt für jedes Element eine eigene Klasse mit eigenen Propertys.
    Zum Thema Reflection:
    Gegeben sind diese Klassen(Tut mir leid dass es C# is):

    C#-Quellcode

    1. public class SomeData
    2. {
    3. public int ID { get; set; }
    4. public string Name { get; set; }
    5. public DateTime Year { get; set; }
    6. public override string ToString()
    7. {
    8. return string.Format("{0}||{1}||{2}", ID, Name, Year.Year);
    9. }
    10. }

    C#-Quellcode

    1. public class OtherData
    2. {
    3. public int ID { get; set; }
    4. public string Name { get; set; }
    5. public DateTime Year { get; set; }
    6. public override string ToString()
    7. {
    8. return string.Format("{0}||{1}||{2}", ID, Name, Year.Year);
    9. }
    10. }

    Und hier nun Reflection:

    C#-Quellcode

    1. List<object> lstData = new List<object>();
    2. SomeData sd = new SomeData { ID = 1, Name = "SD", Year = DateTime.MinValue };
    3. OtherData od = new OtherData { ID = 2, Name = "OD", Year = DateTime.MaxValue };
    4. lstData.Add(sd);
    5. lstData.Add(od);
    6. foreach (var item in lstData)
    7. {
    8. item.GetType().GetProperty("ID").SetValue(item, 3);
    9. item.GetType().GetProperty("Name").SetValue(item, "Reflection");
    10. item.GetType().GetProperty("Year").SetValue(item, new DateTime(5000,1,1));
    11. }
    12. foreach (var item in lstData)
    13. {
    14. Console.WriteLine(item.ToString());
    15. }

    Und das istdas Ergebnis:


    Zum Thema Partial:

    Muss dazu die generierte Klasse nicht bereits als Partial deklariert sein? Wäre dass vom XML-Schema her möglich?
    Dann wäre das natürlich der bessere Weg, da es wesentlich schneller ist als Reflection.

    Analog zu oben:

    C#-Quellcode

    1. public partial class SomeData : IData
    2. {
    3. }
    4. public partial class OtherData : IData
    5. {
    6. }

    C#-Quellcode

    1. interface IData
    2. {
    3. int ID { get; set; }
    4. string Name { get; set; }
    5. DateTime Year { get; set; }
    6. }

    C#-Quellcode

    1. List<IData> lstData = new List<IData>();
    2. SomeData sd = new SomeData { ID = 1, Name = "SD", Year = DateTime.MinValue };
    3. OtherData od = new OtherData { ID = 2, Name = "OD", Year = DateTime.MaxValue };
    4. lstData.Add(sd);
    5. lstData.Add(od);
    6. foreach (var item in lstData)
    7. {
    8. item.ID = 3;
    9. item.Name = "Reflection";
    10. item.Year = new DateTime(5000, 1, 1);
    11. }
    12. foreach (var item in lstData)
    13. {
    14. Console.WriteLine(item.ToString());
    15. }

    Vorrausgesetzt ist, dass SomeData und OtherData bereits Partial sind.
    Achja, das Ergebnis bleibt unverändert :P

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „EaranMaleasi“ ()

    Das Interface würde zusätzliche Methoden definieren, und deine 20 Klassen müssten die implementieren.
    Aber ich glaub besser wäre eine gemeinsame Basisklasse, die du mittels Partial deinen Klassen unterschiebst.

    Aber ich bin nu zu faul, das alles auseinanderzusetzen.
    Du hast ja nu eine hübsche Reflection-Vorlage, und das geht ja auch.

    ErfinderDesRades schrieb:

    Aber ich glaub besser wäre eine gemeinsame Basisklasse, die du mittels Partial deinen Klassen unterschiebst.


    Wie schon gesagt, die Propertys sind automatisch in der Designer-Klasse deklariert. Wenn ich sie in einer Basisklasse zusätzlich deklariere, würde der Compiler doch schimpfen oder?

    Es sind deutlich mehr als 20 Klassen, nur in meinen aktuellen Beispiel sind es 20. Insgesamt werden es bestimmt Hunderte sein.

    @EaranMaleasi
    Das Beispiel mit SetValue habe ich bei MSDN gefunden, mir hat nur die Idee gefehlt, die Klassen in eine List(Of Object) zu packen und den Type dynamisch zu holen.

    Das mit dem Interfache oder einer Basisklasse erscheint mir unmöglich, ohne den Code im Designer anzupassen.

    WhitePage schrieb:

    zusätzlich
    darfst Du sie nicht deklarieren, Du musst sie in eine gemeinsame Basisklasse verschieben.
    Das mit dem zusätzlichen Interface hab ich auch schon gemacht, das geht gut, Du musst dann allerdings die Objekte wieder auf die eigentliche Klasse casten.
    Und Q&D geht das vielleicht sogar mit nem leeren Interface, dies hier compiliert, in VB auch:

    C#-Quellcode

    1. namespace WindowsFormsApplication1
    2. {
    3. public partial class Form1 : Form, TestXxx
    4. {
    5. public Form1()
    6. {
    7. InitializeComponent();
    8. }
    9. }
    10. public interface TestXxx
    11. {
    12. }
    13. }

    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Jetzt muss ich nur noch rausfinden, wie ich den Typ von den List-Elementen rausbekomme :(
    In VB.NET muss ich GetType(Klassname) schreiben, das geht ja nicht.
    EDIT: Es geht auch mit x.GetType wie in C# :D

    RodFromGermany schrieb:

    darfst Du sie nicht deklarieren, Du musst sie in eine gemeinsame Basisklasse verschieben.


    Das geht nicht, weil es ein AUTOMATISCH erstellter Code ist. Bei der nächsten Änderung ist alles futsch.

    WhitePage schrieb:

    AUTOMATISCH
    Klar geht das:

    VB.NET-Quellcode

    1. Public Interface TestXxx
    2. End Interface
    3. Partial Class DEINE_KLASSE ' in einer separaten Datei
    4. Implements TestXxx
    5. End Class
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    RodFromGermany schrieb:

    Klar geht das:

    nicht

    Denn nur implements zu schreiben, reicht nicht. Um auf die Propertys zuzugreifen, muss neben jeder implements stehen, und das wäre Anpassung von zig Tausenden Zeilen Code im Designer, die bei der nächsten Änderung wieder weg wäre. Habe eigentlich schon oben geschrieben.

    @EaranMaleasi
    Das mit Reflection hat in dieser Funktion funktioniert, allerdings, wenn ich in einer anderen Klasse das Ganze auslese, steht da nichts mehr drin :(
    Um auf die Propertys zuzugreifen, muss neben jeder implements stehen

    Muss nicht. Du kannst private Properties erstellen, die auf die eigentlichen Properties zugreifen:

    VB.NET-Quellcode

    1. 'Nicht in der automatisch erstellten Datei:
    2. Public Partial Class FooBar
    3. Private Property IXml_Data As String Implements IXml.Data
    4. Get
    5. Return Data 'Die Data-Property, die im automatisch generierten Code deklariert ist.
    6. End Get
    7. Set
    8. 'Selbes Schema.
    9. End Set
    10. End Class
    11. Public Interface IXml
    12. Property Data As String
    13. End Interface
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    Niko Ortner schrieb:

    Muss nicht. Du kannst private Properties erstellen, die auf die eigentlichen Properties zugreifen:

    Ok, das würde gehen. Bleibt nur Tipparbeit für Hunderte Propertys, die ich mir mit Reflection erspare.

    @EaranMaleasi
    Es ist wohl nicht das Problem der Reflection. Gestern war es schon einmal so, dass die Änderungen an der Stelle später nicht übernommen wurden. Nach VS-Neustart ging es. Heute geht es wieder nicht. Habe nämlich nach der Reflection eine Property probeweise manuell gesetzt, wurde auch später nicht mehr übernommen.
    Interessanterweise funktioniert die Einstellung von Propertys anderer Klassen.