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.
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.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
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:
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.
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.
NuGet Packages im Code auslesen
lock Alternative für async/await
Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.
Und es wird einen Grund geben, warum NHibernate diese Funktion auch nach 15 Jahren nicht eingebaut hat.
Das stringgefrickel widerspricht dem Grundgedanken der Typsicherheit
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.
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).
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
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.
NuGet Packages im Code auslesen
lock Alternative für async/await
Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.