C# Reflektion ohne Basisklasse

-Rayz-

Lieutenant
Registriert
Okt. 2010
Beiträge
909
Hallo,

meine Klasse hat eine Basisklasse und über Reflection mach ich meine Zuweisungen. Allerdings sind dort auch die props der Basisklasse (PropertyChangedBase) mit drin. Diese möchte ich natürlich raus haben.

C#:
 Notification notification = new Notification();
foreach (var prop in notification.GetType().GetProperties().Where(w => ????))

Ich denke ja mal, dass ich das mit where Filtern kann aber... nach was genau?
Mit try catch klappt die Zuweisung zwar aber ich bin sicher, dass das auch anders (richtig) geht.

Vielen dank
 
Eh? 🤔 Zuweisungen über Reflection?

Was um alles in der Welt treibst Du mit OO? Sei so gut und beschreib die Situation mal umfassend. Was hast Du, was willst Du am Ende bekommen?


Reflection = don’t, wie goto auch schon. Plus es ist langsam. R. ist fürs Debugging, nicht für den Betrieb.
 
Ich vermute mal da geht's um eine Zuweisung anhand von Zeichenketten, bspw. aus einer Config?

Vielleicht hilft ja die Eigenschaft "DeclaringType" von PropertyInformation weiter.
Ergänzung ()

RalphS schrieb:
Reflection = don’t, wie goto auch schon. Plus es ist langsam. R. ist fürs Debugging, nicht für den Betrieb.
Das würde das ganze WPF ad acta legen.
 
RalphS schrieb:
Reflection = don’t, wie goto auch schon. Plus es ist langsam. R. ist fürs Debugging, nicht für den Betrieb.
Die Flexibilität die System.Reflection in deine Anwendung bringt ist aber beachtlich.
C#:
var persons = personDataTable.ToObjects<Person>();
var dogs = dogDataTable.ToObjects<Dog>();
Wie ohne Reflection?
 
RalphS schrieb:
Reflection = don’t
Kannst du das bitte begründen? Ich sehe das nämlich definitiv nicht so. Dafür gibt es einem zu viel Flexibilität und macht viele Sachen zu einfach.
Ich sehe ebenfalls nicht, wo Reflection nur fürs Debugging geeignet wäre, ganz im Gegenteil sogar. Reflection-Code zu debuggen empfinde ich eher als schwierig (das wäre einer der Nachteile, die ich aufführen würde).
(Meine Reflection-Kenntnisse beschränken sich auf Java, das dürfte ja aber mehr oder weniger das selbe sein.)
 
Ich nutze Reflection um mein MySQL Result ins Model zu packen.
C#:
 using (MySqlConnection con = new MySqlConnection(_builderLocal.ToString()))
                {
                    await con.OpenAsync();
                    using (MySqlCommand cmd = con.CreateCommand())
                    {
                        cmd.CommandText = @"SELECT * FROM notifications Order By updated_at DESC";
                        using (DbDataReader reader = (await cmd.ExecuteReaderAsync().ConfigureAwait(false)))
                        {
                            while (await reader.ReadAsync())
                            {
                                Notification notification = new Notification();
                                foreach (var prop in notification.GetType().GetProperties())
                                {
                                    try
                                    {
                                        PropertyInfo propertyInfo = notification.GetType().GetProperty(prop.Name);
                                        propertyInfo.SetValue(notification, reader[prop.Name], null);
                                    }
                                    catch (Exception ex)
                                    {
                                        Console.WriteLine(ex.Message);
                                        continue;
                                    }
                                }
                                notifications.Add(notification);
                            }
                        }
                    }
                }

Ich schau mir das mal mit den BindingFlags / DeclaringType an :-)
 
Die BindingFlags klingen ganz gut.

An deiner Stelle würde ich dieses Setzen der Properties der Lesbarkeit halber nochmal in eine separate Funktion schieben, ähnlich dem Muster von @SomeDifferent
 
Funktioniert auch mit den Flags. Vielen Dank dafür :-)
Das setzen der Properties brauch ich nur an der Stelle. Würde ich diese noch woanders brauchen, hätte ich eine separate Funktion gemacht. Zuviel Abstraktion empfinde ich persönlich als nicht so gut lesbar. Kommt natürlich auch wieder sehr auf die Größe der Funktion an.
 
Eventuell solltest du dir mal das Entity Framework anschauen. Du bist nicht der erste, der Datenbank-Objekte als Klassen-Instanzen benötigt. Deswegen fragt ab und an jemand nach dem Hintergrund deines Problems. ;)
 
  • Gefällt mir
Reaktionen: new Account()
Gegen Reflection spricht größtenteils der Performanceaspekt. Daher aus der Praxis heraus: So viel Reflection wie nötig, aber so wenig wie möglich.
In dem Code oben wird beispielsweise für jede einzelne Zeile der Typ analysiert und die Properties ermittelt, obwohl diese immer identisch sind. Du könntest dir also vor der Schleife einmalig die Liste der verfügbaren PropertyInfo-Objekte erstellen und diese immer wiederverwenden.

Ich würde das aber auch mit dem EF lösen, wenn das nicht der einzige Datenbankzugriff ist.

OT:
Mein Reflectionliebling ist ein generic, das aus jeder* Klasse eine deep copy erstellen kann :)
*(jeder halbwegs normal komplexen, es gibt sicherlich Möglichkeiten, die aktuelle Implementierung irgendwie zu überfordern)
 
  • Gefällt mir
Reaktionen: burglar225
Hatte ich gar nicht drauf geachtet... hab die PropertyInfo[] nun ausgelagert und die Zuweisung erfolgt im ctor.

EF nutze ich nur bei größeren Objekten. Hier aber habe ich nur eine einzige Tabelle mit jeweils einem select, update, insert und delete. Da finde ich EF etwas übertrieben für ^^
C#:
private PropertyInfo[] _props;
public NotifactionService()
{
    _props = typeof(Notification).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
}

....
   
    while (await reader.ReadAsync())
    {
        Notification notification = new Notification();
        foreach (var prop in _props)
        {
            try
            {
                prop.SetValue(notification, reader[prop.Name], null);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                continue;
            }
        }
        notifications.Add(notification);
    }

PS: Nun seh ich, dass mein Service einen leichten Schreibfehler drin hat... ^^
 
Zuletzt bearbeitet:
Ha, sorry, hat etwas gedauert, bis ich wieder einen freien Moment gefunden hab.

Stichwort Reflection. Okay, ein kritischer Punkt war ja schon angeführt worden: Performance.
Das Problem ist, daß Reflection in .NET von anfang an zum Debugging gedacht war (note, es geht nicht darum, Reflection zu debuggen, sondern es geht darum, Reflection zu verwenden, um bestehenden Code zu debuggen.) Entsprechend wurde nie Augenmerk auf die Performance gelegt: "Normaler" Code sollte ohne Reflection auskommen, also ist egal, wie performant das ist.

Wo ich grad etwas irritiert bin... sind die angeführten Einsatzbereiche, für die Reflection helfen könnte.
Steh da bestimmt grad mit beiden Beinen auf dem Schlauch, aber dennoch, zur Veranschaulichung:
Reflection verrät mir Details über die existierende Typisierung meines Codes. Was ist was, wer erbt von wo, wenn ich ein object X hab, was steht da drin - sprich ist es eigentlich ein String oder sowas, was ich in ein object reingelegt hatte?

Reflection hat dagegen, zumindest soweit ich informiert bin, mit der Übernahme von sowas wie struct object (als Input aus einer Datenbankzeile) exakt Null zu tun. Wenn ich das in einem Objekt haben will, dann schieb ich das durch einen Konstruktor (dynamisch) oder durch eine ClassFactory(statisch). Was soll mir denn zB GetType() verraten - was will ich damit, wenn ich den Typen doch vorher schon kenne? Außer natürlich ich war so unfähig, in einer Datenbankspalte nicht zu typisieren und nun alle möglichen Werte dort haben zu können.... aber dann stimmt mein Modell nicht und ich hab immer noch keinen triftigen Grund für Reflection.

Generics sind auch immer verlockend. Da muß man tatsächlich aufpassen, weil Generics einerseits und OO andererseits sich einfach beißt. Es ist einfach, T ConvertTo<T>(object input) zu definieren und dann im Funktionskörper mit GetType() und Co um sich zu werfen, damit ConvertTo immer das Richtige tut.
Aber auch dann hat man einen Fehler im Ansatz und sollte vielleicht lieber auf Polymorphie und - da Generics -- jeweils passende Constraints pro Fall ausweichen. Bei Bedarf kann man das ja hintenrum wieder zusammenführen.

Natürlich kann ich an der Stelle nur von mir reden... aber in meinen inzwischen paar Hunderttausend Codezeilen für jeden möglichen kleinen und größeren Keks hab ich, soweit ich das sehe, einmal System.Reflection referenziert und das deswegen, weil mich die Funktionalität als solche interessiert hatte.

PowerShell zum Bleistift erlaubt mir, einfach einen Funktionsnamen in die Konsole zu schreiben (ohne Signatur) und dann sämtliche Overload-Definitions auf die Konsole zu werfen. Oder Intellisense - das macht dasselbe; es gibt keine Listen, sondern es gibt Reflection und ich erfahre beim Tippen, was es überhaupt gibt. Auch das ist im weitesten Sinne Debugging - hier zur Vermeidung von Problemen bereits bei der Entwicklung -- wo man natürlich als Anwender von profitiert.

Aber wenn das alles schon bekannt ist.... fällt es mir schwer, einen echten Sinn für die Verwendung von Reflection auszumachen.
 
Konstruktor mit Parameterliste. Z.B. Lies die Datenbankfelder alle aus und speichere sie in lokalen Variablen bevor du das Notification Objekt erzeugst. Oder was Ähnliches. Einfach niemals Reflection. Leider suggerieren Sprachen wie Python oder JavaScript, dass das ok wäre, so zu programmieren. Es ist weder generisch noch elegant, weil es weniger Zeilen benötigt mit Reflection.
Dein Code hat das Datenmodell und die Datenbankspalten per Namen verknüpft, dafür Typensicherheit geopfert, was man sehr oft sieht als Grund warum Leute Exception Handling verwenden. Da du keine Typensicherheit hast, kannst du nichts wirklich entscheiden, ausser du ermittelst die Typen programmatisch. Deshalb bleibt dir nichts ausser das System eine Ausnahme werfen zu lassen. Beim Auffangen machst du dann nichts. Das sind drei sehr sehr schlechte Dinge.

Angenommen du änderst den Namen einer Spalte in der Datenbank. Du liest alle Zeilen der Datenbank. Plötzlich zeigt dein Programm an, dass alle Werte dieser geänderten Spalte denselben Wert haben, 0, null, "" oder mit was auch immer das entsprechende Feld in Notification initialisiert wird.

Hoffe das hilft dir, dich zu verbessern.

Viel Erfolg und Spass noch.
 
Meine Güte, ich denke dem TE ist schon bewusst, dass das nicht die feine englische Art ist. Er hatte offensichtlich einfach keine Lust, X Properties aufzulisten und zuzuweisen. Wenn das eine Quick & Dirty App ohne große Zukunft ist (nach eigener Aussage wird ja sonst bereits das EF genutzt), braucht man da nun wirklich keine Moralpredigten zu halten.

Dass Reflection (und jetzt sogar noch Generics) generell nicht zu verwenden sind, ist allerdings großer Humbug.
Hier eine Verwendung, die garantiert jeder schon genutzt hat:
https://referencesource.microsoft.com/#system.xml/System/Xml/Serialization/XmlSerializer.cs
 
  • Gefällt mir
Reaktionen: new Account()
Überflüssiges Zitat (Bitte die Forumregeln beachten!)
Enurian schrieb:
Meine Güte, ich denke dem TE ist schon bewusst, dass das nicht die feine englische Art ist. Er hatte offensichtlich einfach keine Lust, X Properties aufzulisten und zuzuweisen. Wenn das eine Quick & Dirty App ohne große Zukunft ist (nach eigener Aussage wird ja sonst bereits das EF genutzt), braucht man da nun wirklich keine Moralpredigten zu halten.

Dass Reflection (und jetzt sogar noch Generics) generell nicht zu verwenden sind, ist allerdings großer Humbug.
Hier eine Verwendung, die garantiert jeder schon genutzt hat:
https://referencesource.microsoft.com/#system.xml/System/Xml/Serialization/XmlSerializer.cs

Das hat doch nichts mit Moralpredigt zu tun. Was ist denn das für eine Einstellung zum Lernen?

Reflection: Ein Sprachkonzept, um die Sprache selbst zu manipulieren.
Natürlich verwendet Microsoft dies, um die Bibliotheken zu schreiben. D.h. nicht, dass es eine gute Idee ist für die Endnutzer der Sprache ebenfalls Reflection zu verwenden, wenn man nicht weiss, wie man das Problem anders löst. Falscher Umkehrschluss.

Happy learning und viel Spass
 
nerdalicious schrieb:
Natürlich verwendet Microsoft dies, um die Bibliotheken zu schreiben. D.h. nicht, dass es eine gute Idee ist für die Endnutzer der Sprache ebenfalls Reflection zu verwenden, wenn man nicht weiss, wie man das Problem anders löst. Falscher Umkehrschluss.
Und man selbst darf keine Bibliotheken / ähnlich nützliche Funktionalitäten schreiben?
Sehr seltsames Argument.
 
  • Gefällt mir
Reaktionen: new Account()
Enurian schrieb:
Zitat entfernt - Bitte Regeln beachten!​

Das ist wieder ein falscher Umkehrschluss. Hier ist ein Link zu den Grundlagen der Aussagenlogik ;) Hat keiner gesagt, man darf keine Bibliotheken schreiben. Ich will nur aufzeigen, was man sich sonst überlegen kann. Vielleicht möchte Threadersteller ja mal beruflich Software schreiben, wer weiss?

Es geht um Software Design. Ich möchte nur helfen :)
 
Zuletzt bearbeitet von einem Moderator: (Zitat des unmittelbar vorangestellten Beitrags entfernt)
Du willst mir was über Logik erzählen, verstehst aber nicht einmal, dass es hier um zwei unterschiedliche Dinge geht:
1. Der Code vom TE, der wahrscheinlich funktioniert, aber weder schön noch empfehlenswert ist - das ist soweit unstrittig.
2. Die allgemeine Verteufelung von Reflection, die grober Unsinn ist. Wo es sinnvoll ist, wird es auch verwendet und ist dort sehr nützlich. Es ist sicherlich auf die Nachteile hinzuweisen und dass zunächst andere Lösungen gesucht werden sollten. Das als Teufelszeug abzutun ist weder "OO", noch macht es einen zu einem besseren Programmierer (eher zu einem mit einem beschränkten Horizont).
 
  • Gefällt mir
Reaktionen: new Account()
Nur zur Klarstellung, ich hab nicht gemeint, Generics seien nicht zu verwenden.

Sie stehen aber OO konträr gegenüber.
Oo: Hierarchisch von Superklasse nach unten per Derivation.
Generics: Seitwärts und Aufwärts-Definition, insbes aber nicht nach unten.

Klasse Fahrzeug und Derivate Pkw und LKW:
— Oo definiert Gemeinsamkeiten in Fahrzeug und Deltas in den beiden Klassen. Es gibt keinen Verweis auf Methodenebene zwischen Pkw und LKW.

— Generics dagegen schreiben Methoden ggfs irgendwohin und interessieren sich bestenfalls mit where T: className für den hierarchischen Bezug. DoorOpen<T>() where T:Fahrzeug frißt Unterklassen, hier Pkw und Lkw. Ohne Generics muß man eine Methode DoorOpen() in jeder Unterklasse definieren, wenn man das in Fahrzeug nicht für alle Unterklassen pauschal abhandeln kann - und weder kennt Fahrzeug Pkw oder LKW noch kann man aus Pkw die Methode DoorOpen aus LKW aufrufen. Die existieren dort einfach nicht.

Deshalb gibt es ja Generics. Sie fügen sich aber nicht in OO ein, ebensowenig wie WQL und Linq.


— Generics verlocken aber eben, WEIL sie solche Freiheiten erlauben, und laden dazu ein, weiter mit OO zu brechen. Wenn ich <T> hab, dann kann ich natürlich switch tyeof() sagen und dann per Reflection case-by-case rangehen. Generics haben ja keine inhärenten Constraints, mein T kann erstmal alles sein, wenn ich nicht explizit was anderes verlange.b
Deswegen die Verlockung, OO allgemein über den Haufen zu werfen. Man muß das in Generics nicht beachten, da die selber nicht OO konform sind, und mit Reflection obendrauf kann ich machen was ich will... aber sollte ich halt nicht, weil hinten bloß noch Spaghetti rauskommen und man auch goto hätte sagen können.

Nichts davon verlangt danach, Generics nicht zu verwenden. Ich hab selber schon lange sämtlichte object[] durch IEnumerable<object> oder List<object> ersetzt und will das auch nicht missen.
Man muß nur bedacht rangehen. Das ist alles.
 
Zuletzt bearbeitet von einem Moderator:
  • Gefällt mir
Reaktionen: nerdalicious
Zurück
Oben