DCSIMG
How To Get A Property Name Using Lambda Expression in C# 3.0 - Smallfish

Smallfish

Tips, Tricks, Shticks & Anything That Can Help You Be better Developer

How To Get A Property Name Using Lambda Expression in C# 3.0

During development of WPF application using M-V-VM design pattern (by Josh Smith on MSDN Mag.) I came across a problem of refactoring the view model classes, especially the properties’ names. The view model classes are implementing the INotifyPropertyChanged interface by inheriting from a helper NotifyPropertyChanged base class which have a method to raise the property changed event called ‘SendPropertyChanged’. That method gets “propertyName” parameter which is a string, and this was the problem:

My view model properties looks like:

        private string m_name;
        public string Name
        {
            get 
            {
                return m_name;
            }
            set
            {
                if (m_name != value)
                {
                    m_name = value;
                    SendPropertyChanged("Name");
                }
            }
        }

the problem here is if I change the property name to “CustomerName” I must ensure to correct the string name in the method parameter. Even worse, if for some reason another method / property is calling ‘SendPropertyChanged’ for the ‘Name’ property it will cause invisible problems (you will see it on the screen, but very difficult to spot). And then:

Lambda Expression to the rescue!

What I wanted to achieve is:

        private string m_name;
        public string Name
        {
            get 
            {
                return m_name;
            }
            set
            {
                if (m_name != value)
                {
                    m_name = value;
                    SendPropertyChanged(()=> this.Name);
                }
            }
        }

Note the bolded “() => this.Name”, this will ensure that if anyone changes the name of the property the build will fail (or, using the Refactoring->Rename in VS will change it automatically). After a lot of searches I found the way to do this (in Bernardo Heynemann blog post):

        private string GetPropertyName<T>(Expression<Func<T>> property)
        {
            var propertyInfo = (property.Body as MemberExpression).Member as PropertyInfo;
            if (propertyInfo == null)
            {
                throw new ArgumentException("The lambda expression 'property' 
should point to a valid Property");
            }
 
            var propertyName = propertyInfo.Name;
 
            return propertyName;
        }

Note the parameter type Expression<Func<T>> – whenever you cast a delegate (in this case of Func<T>) into Expression you are getting the associated Expression Tree and not the delegate itself. The call is clean and nice due to another feature of C# 3.0 ‘Type inference’ the compiler determines the type of T parameter and does not require us to add the ugly curly brackets.

Enjoy the new revolution!

תוכן התגובה

Sergey Ivanchenkov, The Russian כתב/ה:

You are DA MAN! (i.e. "The Man" in Black vibe).

I've pasted your method snippet, changed access modifier, called it in code and "YES!" it worked. I am gonna use it going forward. I consider myself very good with C# but today I learned from you something new. That should be better than any other reward right here :))

For poster "B":

here is a code example on how to use his method:

string propName = YourNamespace.YourStaticClass.MethodNameShownAbove(()=>ClassInstanceWithProp.PropertyWhichRequiresNameFound);

S.I.

# November 2, 2009 11:29 PM

Hans 'herzl' כתב/ה:

using System;

using System.Linq.Expressions;

public partial class Default : System.Web.UI.Page

{

   String[] GetNames<T>(params Expression<Func<T>>[] BLOCKED EXPRESSION

   {

       var array = new String[expressions.Length];

       for (var i = 0; i < expressions.Length; i++)

       {

           var item = expressions[i];

           var memberExpression = item.Body as MemberExpression;

           array[i] = memberExpression.Member.Name;

       }

       return array;

   }

   protected void Page_Load(Object sender, EventArgs e)

   {

       if (IsPostBack)

       {

           return;

       }

       var obj = new Employee();

       var array0 = GetNames(() => obj.LastName); //Gets an array or 1 element

       var array1 = GetNames(() => obj.LastName, () => obj.FirstName); //Gets an array of 2 elements

       //var array2 = GetNames(() => obj.Id, () => obj.LastName, () => obj.FirstName);

       //  Error, because property data types are differents

       //  I need a method that gets String array from differents property types

   }

}

public class Employee

{

   public Employee()

       : base()

   {

   }

   public Int32 Id

   {

       get;

       set;

   }

   public String LastName

   {

       get;

       set;

   }

   public String FirstName

   {

       get;

       set;

   }

}

# March 4, 2010 9:45 PM

Maxence Bonhomme כתב/ה:

Great thank you!

# July 1, 2010 1:15 PM
שלח תגובה

(שדה חובה)  

(שדה חובה)  

(אופציונלי)

(שדה חובה) 

Please add 1 and 6 and type the answer here:


Enter the numbers above: