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
Expression<Func<object>> aus String erstellen
Net.Dev
myCSharp.de - Member



Dabei seit:
Beiträge: 6

Themenstarter:

Expression<Func<object>> aus String erstellen

beantworten | zitieren | melden

Hallo =)

Es geht darum, dass ein

Expression<Func<object>>
aus einem String ("() => obj.Id") erstellt werden soll.

Zur Verfügung im Projekt steht "System.Linq.Dynamic.Core".

Für

Expression<Func<T, object>>
funktioniert es ohne Probleme. Nur tut sich "Dynamic Linq" anscheinend schwer, wenn kein "T" übergeben wird.

Daher meine Frage, ob sich jemand mit "Dynamic Linq" auskennt und mir sagen kann, ob das so überhaupt möglich ist.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15510
Herkunft: BW

beantworten | zitieren | melden

Darf man Fragen, was der Anwendungsfall dafür sein soll?
Zitat
Nur tut sich "Dynamic Linq" anscheinend schwer, wenn kein "T" übergeben wird.
Damit tut sich weniger der Namespace schwer als die Methode.
Func benötigt immer einen Rückgabewert; es gibt kein Func-Delegate ohne Rückgabe.
Willst Du keine Rückgabe, dann musst eine Action verwenden.
private Nachricht | Beiträge des Benutzers
Net.Dev
myCSharp.de - Member



Dabei seit:
Beiträge: 6

Themenstarter:

beantworten | zitieren | melden

Hi Abt,

Danke für deine Antwort.

Genau geht es hier um NHibernate; genauer um QueryOver und Select.

Die Select-Funktion ist einmal überladen und nimmt die folgenden Parameter an:
- Select(Expression<Func<T, object>> expression) - Es wird ein Property der eigentlichen Entität übergeben
- Select(Expression<Func<object>> expression) - Es wird ein Property einer JOIN-Entität übergeben

Um das dynamischer zu gestalten bin ich hier gerade dran, die Expression als String übergeben zu können. Die erste Überladung (mit T) funktioniert ohne Probleme und es wird die korrekte Expression erstellt.

Wenn hier jetzt auf eine Entität in einem JOIN verwiesen wird, wird diese mit

 JoinEntity joinAlias = null; queryOver.JoinAlias(..., () => joinAlias);
"registriert". Danach kann mit Select(() => joinAlias.Id) auf Properties darin verwiesen werden. Und hier würde ich den Parameter gerne dynamisch aus einem String generieren lassen.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Net.Dev am .
private Nachricht | Beiträge des Benutzers
Palladin007
myCSharp.de - Member

Avatar #avatar-4140.png


Dabei seit:
Beiträge: 1411
Herkunft: NRW

beantworten | zitieren | melden

Lass doch genau diesen Teil der Query als Expression der Methode übergeben?

private void DoSomething<TBar>(Expression<Func<Foo, TBar>> getBar)
{
    var bars = QueryFoo()
        .Select(getBar);
}

Wenn Du danach noch mehr machen willst, könntest Du es mit generic Constraints testen, indem Du den generischen Typ auf eine Basisklasse einschränkst. Dann kannst Du nach dem Select mit allen Membern der Basisklasse arbeiten.
Ich bin mir aber nicht ganz sicher, ob Generics vielleicht noch andere Auswirkungen auf die Expression haben, also mit Vorsicht genießen.

Sowas würde ich nie per String machen.
Dann lieber die Expression per Hand zusammenbauen, das ist hakelig, aber um Längen besser, als einen Parser zu verwenden, bei dem Du sämtliche Compiler-Sicherheiten verlierst.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Palladin007 am .
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 10042

beantworten | zitieren | melden

Und es wird einen Grund geben, warum NHibernate diese Funktion auch nach 15 Jahren nicht eingebaut hat.

Das stringgefrickel widerspricht dem Grundgedanken der Typsicherheit
private Nachricht | Beiträge des Benutzers
Net.Dev
myCSharp.de - Member



Dabei seit:
Beiträge: 6

Themenstarter:

beantworten | zitieren | melden

Hallo Palladin007 und FZelle,

bzgl. der Typ- und Compilersicherheit kann ich euch nur zustimmen und in 2021 (auch vorher schon ) sollte man auf String-Übergaben, soweit möglich, verzichten.

Aber leider sind ja bekanntlicherweise die Aufgabenstellungen und Herausforderungen auf die man in der echten Welt stößt nicht immer so schön zu lösen wie es nach aktuellem Stand der Technik möglich wäre

Hier geht es mir nicht darum, einen "Umweg" in einen OR-Mapper zu bauen, sondern eine aktuelle Aufgabe zu lösen. Die Variablennamen, die als String übergeben werden sind zu 100% valide und geprüft, so dass dort kein Fehler passieren kann.

@Palladin007:
Zitat
Sowas würde ich nie per String machen.
Dann lieber die Expression per Hand zusammenbauen, das ist hakelig, aber um Längen besser, als einen Parser zu verwenden, bei dem Du sämtliche Compiler-Sicherheiten verlierst.
Kannst du mir hier einen Denkanstoß geben? Output muss ein Expression<Func<object>> sein; als Input habe ich Propertyname, Alias-Instanzname und Alias-Instanztyp.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Net.Dev am .
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15510
Herkunft: BW

beantworten | zitieren | melden

Man kann in dem Zug es aber auch so sehen:
Deine Aufgabe als Entwickler ist es aber auch durchaus diese, dass Du Alltags-Anforderungen reviewen und in technische Lösungen backen musst.
Sagt keiner, dass Du das 1:1 direkt so übernehmen musst.

Ich sehe das wie Palladin007, dass Du durchaus die Expression selbst bauen kannst, ohne sie zu parsen.
Letzten Endes funktionieren so die meisten SDKs, die mit Expressions arbeiten (zB. auch Such-Engines; auch die neuen dieses Forums).
private Nachricht | Beiträge des Benutzers
Palladin007
myCSharp.de - Member

Avatar #avatar-4140.png


Dabei seit:
Beiträge: 1411
Herkunft: NRW

beantworten | zitieren | melden

private void Abc()
{
    DoSomething<MyClass>(myObj => myObj.Data);
}
private void DoSomething<TBar>(Expression<Func<Foo, TBar>> getBarExpression)
{
    var bars = QueryFoo()
        .Select(getBarExpression);
}

IQueryable bzw. die Erweiterungsmethoden in der Queryable-Klasse machen nichts anderes, als solche Expressions zu bauen, nHibernate interpretiert das dann.
Mein Beispiel oben ist die einfache Variante, die mit Lambda genutzt werden kann, man kann die Expression aber auch dynamisch anhand von Reflection-Daten aufbauen.
Wichtig ist nur, dass das Ergebnis das Gleiche ist, wie das, was man bei normaler LINQ-Nutzung raus bekommen würde, damit NHibernate es auch versteht.

Expressions sind vielleicht nicht super einfach zu verstehen, aber definitiv besser als String-Interpretation.
Oder Du arbeitest mit der einfachen Variante, wie oben gezeigt.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Palladin007 am .
private Nachricht | Beiträge des Benutzers