www.rolandk.de
- Aktuelle Themen zu .Net -
Achtung: Hier handelt es sich um meine alte Seite.
Die aktuelle ist unter folgendem Link erreichbar: www.rolandk.de/wp/
Home Blog Playing with Expressions




















































Playing with Expressions
Dienstag, den 13. September 2011 um 04:38 Uhr

In der Version 3.5 wurde zusammen mit Linq die Expression-API eingeführt. Der Grundgedanke dahinter ist es, Code in einem baumartigen Objektmodell abzubilden, damit er leicht analysiert oder automatisiert erzeugt werden kann. Linq-To-Sql etwa macht im Hintergrund nichts anderes, als den Code zu analysieren und daraus ein Sql-Statement zu basteln. Dieses Vorgehen kann aber auch für ganz andere Situationen verwendet werden.

 

Besonders wenn es um die Entwicklung von Oberflächen geht, sieht man folgendes recht häufig:

  1. public string TestString
  2. {
  3. get{ return m_testString; }
  4. set
  5. {
  6. if(m_testString != value)
  7. {
  8. m_testString = value;
  9. RaisePropertyChanged("TestString");
  10. }
  11. }
  12. }

Die Eigenschaft kann an die Oberfläche gebunden werden und informiert die Oberfläche per RaisePropertyChanged automatisch, wenn sich der Wert geändert hat. Aber: Zum Einen ist es viel Tipparbeit und zum anderen stört das harte "TestString". Gibt es denn keine Möglichkeit, dem Compiler zu sagen, dass es sich um den Namen der Eigenschaft handelt? Standardmäßig nicht, aber mit Expression gibt es da einen Trick. Man schaue sich dazu nachfolgende Methode an:

  1. /// <summary>
  2. /// Gets the name of the member defined in given expression.
  3. /// Pass something like () => this.m_testMember to get the name "m_testMember".
  4. /// </summary>
  5. /// <param name="getMemberAction">Action for getting the member.</param>
  6. public static string GetMemberName(Expression<Func<object>> getMemberAction)
  7. {
  8. MemberExpression memberExpression = getMemberAction.Body as MemberExpression;
  9. if (memberExpression != null)
  10. {
  11. return memberExpression.Member.Name;
  12. }
  13. else
  14. {
  15. throw new ArgumentException("Body of given expression is not a MemberExpression!");
  16. }
  17. }

Ohne jetzt viel über die Methode zu sagen.. die Get/Set Eigenschaft könnte damit so entwickelt werden:

  1. public string TestString
  2. {
  3. get{ return m_testString; }
  4. set
  5. {
  6. if(m_testString != value)
  7. {
  8. m_testString = value;
  9. RaisePropertyChanged(GetMemberName(() => TestString));
  10. }
  11. }
  12. }

Sieht schon anders aus, aber was passiert? Bei der Methode GetMemberName wird eine Expression erwartet. Wird der Methode ein Lambda-Ausdruck übergeben, wandelt der Compiler automatisch den Inhalt des Lambdas in eine Expression um, die anschließend von der Methode GetMemberName analysiert werden kann. Innerhalb der Methode wird lediglich nachgeschaut, ob der Inhalt der Methode eine MemberExpression ist, und falls ja, wird der Name des betroffenen Members zurückgegeben. Für den Fall, dass der Lambda andere Inhalte hat (wie etwa ein Methodenaufruf oder ähnliches), so wird einfach eine Exception geworfen.

 

Der hier vorgestellte Trick ist eine elegante Lösung, um an den Namen einer Eigenschaft zu kommen, ohne ihn direkt als String angeben zu müssen. Natürlich könnte man die Get/Set Methoden hier vom Code-Umfang noch weiter kürzen, dies soll aber nicht Gegenstand dieses Beitrags sein.

 

Kommentar hinzufügen

Ihr Name:
Kommentar: