Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Zugriff auf Klasse mittels String-Variable
Stoffel000
myCSharp.de - Member



Dabei seit:
Beiträge: 4

Themenstarter:

Zugriff auf Klasse mittels String-Variable

beantworten | zitieren | melden

Hallo liebes Forum,
in diesem Forum habe ich schon oft Hilfe gefunden. Doch leider diesmal nicht. Ich bin ziemlich neu in der Programmierung und habe momentan ein Problem an dem ich mir die Zähne ausbeiße.


List<Tuple<string, string>> list = new List<Tuple<string,string>>();
TextBox.Text = MeineKlasse.[hier sollte der 2. wert der liste stehen];

Die Klasse selbst und auch die List ist kein Problem. Das funktioniert soweit. Nun meine Frage: Ist es möglich aus dem String der List auf ein Objekt der Klasse zuzugreifen?

Dies ist ein vereinfachtes Beispiel. Die Klasse selbst hat über 400 Objekte und die List hat 6 Strings. Ein direkter Zugriff wäre zwar möglich aber ein sehr hoher Programmieraufwand.

Ich hoffe ich habe nichts vergessen. Falls doch, bitte einfach nachfragen.

Danke im Voraus.

LG Stoffel000
private Nachricht | Beiträge des Benutzers
JimStark
myCSharp.de - Member

Avatar #dOpLzh7hN1az1g0eGRc0.jpg


Dabei seit:
Beiträge: 297

beantworten | zitieren | melden

Zitat von Stoffel000

Die Klasse selbst und auch die List ist kein Problem. Das funktioniert soweit. Nun meine Frage: Ist es möglich aus dem String der List auf ein Objekt der Klasse zuzugreifen?



Das hört sich verdächtig nach falscher Planung an, zeig doch mal deine Klasse.
Du willst in Abhängigkeit eines Strings der Liste auf ein bestimmtes Feld der Klasse zugreifen?
private Nachricht | Beiträge des Benutzers
ClaraSoft
myCSharp.de - Member



Dabei seit:
Beiträge: 42

beantworten | zitieren | melden

Hallo,

Hast du dir mal die Klasse Dictionary<Tkey, TValue> angeschaut, damit dürftest du eher ans Ziel zu kommen, weil du dann dein Tuple nicht mehr in einer Liste wrappen müsstest.

Hier die Doku zu Dictionary:
Dictionary<TKey,TValue> Klasse (System.Collections.Generic)

Grüße
private Nachricht | Beiträge des Benutzers
Stoffel000
myCSharp.de - Member



Dabei seit:
Beiträge: 4

Themenstarter:

beantworten | zitieren | melden

Hallo JimStark,

hier ein kleiner Ausschnitt meiner Klasse:


 public class ClassDatenblatt_DC
    {
        public int Id { get; set; }
        public string Zeitstempel { get; set; }
        public string Ersteller { get; set; }
        public Nullable<int> Status { get; set; }
        public string Datum { get; set; }
        public string Artnr { get; set; }
        public string Berechnungsnummer { get; set; }
        public Nullable<int> Version { get; set; }
        public Nullable<int> Aenderung { get; set; }
        public string Stromrichter { get; set; }
....
}
und hier ein Ausschnitt der List:


 wandlerlistDc = new List<Tuple<string, string, string, string, string, string>>
            {
                new Tuple<string, string, string, string, string, string>("abnummer", "", "", "", "", ""),
                new Tuple<string, string, string, string, string, string>("pos", "", "", "", "", ""),
                new Tuple<string, string, string, string, string, string>("status", "status", "", "", "", ""),
                new Tuple<string, string, string, string, string, string>("erst_dat", "datum", "", "", "", ""),
                new Tuple<string, string, string, string, string, string>("a1", "berechnungsnummer", "", "", "", ""),
                new Tuple<string, string, string, string, string, string>("v1", "version", "", "", "", ""),
....
}

Wenn aus meiner List der 5. Eintrag an der Reihe ist, soll a1 als Label angezeigt werden und die Berechnungsnummer als Wert der Klasse geladen werden (würde dem 7. Eintrag der Klasse entsprechen.)
Der Zugriff auf den Wert der Klasse funktioniert mit:


internal Klassenbibliothek.ClassDatenblatt_DC neuerDatensatzBearbeiten = new Klassenbibliothek.ClassDatenblatt_DC(); //erstellen einer Ableitung der Klasse
TextBox.Text = neuerDatensatzBearbeiten.berechnungsnummer;
Da ich aber über den String der List zugreifen möchte (um mir sehr viel Arbeit zu ersparen) müsste das in etwa so aussehen:


internal Klassenbibliothek.ClassDatenblatt_DC neuerDatensatzBearbeiten = new Klassenbibliothek.ClassDatenblatt_DC(); //erstellen einer Ableitung der Klasse
TextBox.Text = neuerDatensatzBearbeiten.[StringDerListeFürDenZugriff];

Wie gesagt ich bin nicht wirklich fit in der Programmierung. Sollte ich einen komplett falschen Ansatz gewählt haben, dies bitte auch sagen und evtl. einen Vorschlag machen wie ich es besser machen könnte.

Danke.
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 4191

beantworten | zitieren | melden

Hallo,

das Stichwort dafür ist Reflection, s.a. C# Reflection Examples (bei dir also mittels PropertyInfo).
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Th69 am .
private Nachricht | Beiträge des Benutzers
Stoffel000
myCSharp.de - Member



Dabei seit:
Beiträge: 4

Themenstarter:

beantworten | zitieren | melden

Hallo Th69,

ich habe mir soeben den verlinkten Beitrag angesehen. Leider verstehe ich das nicht ganz. Kannst du mir ein Beispiel geben?

Danke

Grüße Stofffel000
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 4191

beantworten | zitieren | melden

Da wirst du dich selber ein bißchen einlesen müssen.
Die Hauptmethode für dich ist Type.GetProperty sowie PropertyInfo.GetValue (dort gibt es auch jeweils Beispiele).

PS: Die Strings für die Eigenschaftsnamen müssen aber exakt übereinstimmen (d.h. auch Groß-/Kleinschreibung).
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Th69 am .
private Nachricht | Beiträge des Benutzers
Stoffel000
myCSharp.de - Member



Dabei seit:
Beiträge: 4

Themenstarter:

beantworten | zitieren | melden

Danke für die Hilfe. Da werde ich dann mal lesen und googlen um das zu verstehen. Die Eigenschaftsnamen setzte ich mit ToLower() alle auf Kleinbuchstaben. Somit sind sie dann gleich.

Danke, danke, danke. Hast mir sehr geholfen.

Grüße
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 4191

beantworten | zitieren | melden

Wenn die Eigenschaft Status heißt, so mußt du auch "Status" bei GetProperty angeben (und nicht "status")!
Eigenschaftsnamen in C# sollten laut C# Coding Conventions auch genau so benannt sein (d.h. mit einem großgeschriebenen Anfangsbuchstaben), dies solltest du also nicht ändern.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Th69 am .
private Nachricht | Beiträge des Benutzers
JimStark
myCSharp.de - Member

Avatar #dOpLzh7hN1az1g0eGRc0.jpg


Dabei seit:
Beiträge: 297

beantworten | zitieren | melden

Würde es gar nicht so kompiliziert machen:


enum Field
{
 abnummer,
 pos,
...
}

wandlerlistDc = new List<Tuple<Field, string, string, string, string, string>>
            {
                new Tuple<string, string, string, string, string, string>(Field.abnummer, "", "", "", "", ""),
...
....



und in der Klasse:


public string GetOrderInfo(Field field)
{
   switch(field)
      {
      case field.abummer:
        return this.Artnr;
...

Dann könntest du es da auch richtig formatieren, ist vielleicht mehr Schreibarbeit, fände ich aber einfacher
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16206

beantworten | zitieren | melden

Für sowas erstellt man eigentlich Metadata-Informationen/Klassen, denn der bisherige Ansatz und über Reflection skaliert nicht.
Die Änderung an einem String, an der Klasse und Co würde dazu führen, dass es knallt, weil Du es auch nicht validieren kannst.
Report-Komponenten machen das quasi in der Designer-Time. Neuere Reports gehen den Weg von Source Code Generators, der hier wahrscheinlich auch verwendet werden kann.

Der Aufbau (von der Klasse und auch den Tuples) ist zudem ein Zeichen bzw ein Hinweis, dass was an der Struktur / Architektur womöglich grundlegend nicht stimmen könnte.
Was Du mit "die Klasse hat über 400 Objekte" erschließt sich mir inbesondere aufgrund von "Objekt" nicht. Riecht aber auf alle Fälle auch eher fischig.

Reflection ist ein vergleichsweise komplexes Thema, das Du sicherlich nicht in den 10 Minuten zwischen Antwort und Post durchgelesen oder gar verstanden haben kannst.
Das wird Dich eher paar Tage kosten; lohnt sich aber generell sowieso :-)
- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers
c#arp
myCSharp.de - Member



Dabei seit:
Beiträge: 10
Herkunft: Mannheim

beantworten | zitieren | melden

Mit Reflection könntest Du es so lösen (ist ungetestet, evtl noch Fehler...)
Würde mit Groß/Kleinschreibungsvariationen umgehen können.


public static class CallByNameExtensions {
    public static object GetValue(this object instance, string propertyName) {
        try {
            return instance.GetType().InvokeMember(propertyName, BindingFlags.IgnoreCase|BindingFlags.GetProperty|BindingFlags.Instance|BindingFlags.Public, null, instance, null);
        } catch {
            return null;
        }
    }
}


Aufruf:


var blatt = new ClassDatenblatt_DC();
blatt.Id = "42";
blatt.BerechnungsNummer = "0815/4711";

var id = blatt.GetValue("id");  //id enthält 42
var bNummer = blatt.GetValue("berechnungsnummer"); //bNummer enthält 0815/4711
private Nachricht | Beiträge des Benutzers
Palladin007
myCSharp.de - Member

Avatar #avatar-4140.png


Dabei seit:
Beiträge: 1536
Herkunft: Düsseldorf

beantworten | zitieren | melden

Bei einem Catch, das einfach nur irgendeinen Default zurückgibt, bekomme ich Bauchschmerzen.

Gerade beim Thema Reflection sind die Namen fest definiert, da ist nichts dynamisch. (Naja, außer man lädt/generiert zur Laufzeit, aber das ist hier nicht der Fall)
Ist ein Name falsch, dann ist er nun mal falsch und definitiv ein Fehler zur Entwicklungszeit. So ein Fehler sollte nicht geschluckt werden!
Ich persönlich arbeite daher möglichst mit nameof (Docs), dann passt der Compiler für mich auf.

Viel eher könnte man eine "TryGetValue"-Methode daraus machen und dann entsprechend reagieren, wenn der Wert nicht gefunden wird. Dann aber bitte prüfen, ob's die Property gibt und nicht mit Exceptions für den Kontrollfluss arbeiten.
Oder man lässt die Exception fliegen (kapselt sie ggf. in einer Exception mit sprechendem Namen und mehr Infos) und erfährt dann auch auf Anhieb, was das Problem war.
Konkrete Exceptions an der konkreten Position sind sehr viel leichter zu behandeln, als ein Fehler wie "irgendwo ist irgendwann ein null entstanden".

Außerdem habe ich die Erfahrung gemacht, dass solche allgemeinen ExtensionMethods früher oder später zu Chaos führen.
Bedenke, dass sie für alles gelten (object) und Du sie daher auch überall aufrufen kannst, was einerseits nervig werden und andererseits zu ungünstigen Abhängigkeiten führen kann.
Abgesehen davon ist das Ding auch nichts anderes als eine ganz normale statische Methode mit ein bisschen Compiler-Zucker und den gleichen Nachteilen, die jede statische Methode hat. Bei diesem Beispiel ist das kein Problem, sobald aber etwas spezifischere Logik dazu kommt, wird es zu einem Problem, das Du nicht mehr so einfach weg bekommst.

Das heißt, wenn es auf eine solche Reflection-Lösung hinauslaufen sollte:
Einfach eine normale private Methode in die Klasse, in der sie gebraucht wird.
Und ein sinnvolles Fehlerhandling indem z.B. geprüft wird, ob es die Property auch wirklich gibt und ein Setter da ist.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16206

beantworten | zitieren | melden

Ich kann da Palladin007 nur beipflichten: so ein Vorgehen hat mehrere Design Fehler bzw. Design Risiken.
Reflection an für sich ist schon ein gewisser Overhead und Risiko; das muss man nicht künstlich durch stringifcation und objectification noch verschlimmern.

Der Grund warum es überhaupt Source Code Generators gibt sind eben die Risiken von Reflections (und noch 2-3..72 andere Dinge wie Performance).
Nehmt also den Weg des .NET Ökosystems an und verzichtet auf Reflections, wo es nur geht - und nutzt moderne Mittel.
Zitat von Palladin007
Dann aber bitte prüfen, ob's die Property gibt und nicht mit Exceptions für den Kontrollfluss arbeiten.
Der eigentliche Grund dieser Antwort: das ist ein enorm richtiger und wichtiger Satz, den man unbedingt betonen muss!
- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers