Laden...

Expression<Func<object>> aus String erstellen

Erstellt von Net.Dev vor 3 Jahren Letzter Beitrag vor 3 Jahren 557 Views
N
Net.Dev Themenstarter:in
6 Beiträge seit 2020
vor 3 Jahren
Expression<Func<object>> aus String erstellen

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.

16.806 Beiträge seit 2008
vor 3 Jahren

Darf man Fragen, was der Anwendungsfall dafür sein soll?

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.

N
Net.Dev Themenstarter:in
6 Beiträge seit 2020
vor 3 Jahren

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.

2.078 Beiträge seit 2012
vor 3 Jahren

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.

F
10.010 Beiträge seit 2004
vor 3 Jahren

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

Das stringgefrickel widerspricht dem Grundgedanken der Typsicherheit

N
Net.Dev Themenstarter:in
6 Beiträge seit 2020
vor 3 Jahren

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:

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.

16.806 Beiträge seit 2008
vor 3 Jahren

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).

2.078 Beiträge seit 2012
vor 3 Jahren
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.