Static Reflection: Say What?

There’s a new oxymoron going around call Static Reflection. The basic gist is that by using expression trees you can do things that appear to be dynamic but in reality are checked at compile time. Like for instance, getting the name of a property for firing an INotifyPropertyChanged.PropertyChanged event. My colleague, Jon Fuller, showed me his code for Method Guards and my first comment was that this would be a great tool for implementing INotifyPropertyChanged. He informed me that he already went there and showed me that code as well.

I wasn’t too happy with the idea of wasting your sole base class on NotifyPropertyChanged so I suggested that we use extension methods instead. After a bit of finagling with the framework (Events don’t like to be fired from outside their declaring class), here is the result:

        public static void SetProperty<T>(
		this INotifyPropertyChanged source, 
		Expression<Func<T>> propExpr,
		Expression<Func<T>> fieldExpr,
		T value)
        {
            source.SetProperty(
		propExpr, 
		fieldExpr, 
		value, 
		() => { });
        }

        public static void SetProperty<T>(
		this INotifyPropertyChanged source,
		Expression<Func<T>> propExpr,
		Expression<Func<T>> fieldExpr,
		T value,
		Action doIfChanged)
        {
            var prop = 
		(PropertyInfo)
		((MemberExpression)propExpr.Body).Member;
            var field =
		(FieldInfo)
		((MemberExpression)fieldExpr.Body).Member;
            var currVal = (T)prop.GetValue(source, null);
            if (currVal==null && value==null)
                return;
            if (currVal==null || !currVal.Equals(value))
            {
                field.SetValue(source, value);
                var eventDelegate =
			(MulticastDelegate) 
			source.GetType().GetField(
				"PropertyChanged",
				BindingFlags.Instance | 
				BindingFlags.NonPublic).
				GetValue(source);
                Delegate[] delegates = 
			eventDelegate.GetInvocationList();
                var args = new PropertyChangedEventArgs(prop.Name);
                foreach (Delegate dlg in delegates)
                {
                    dlg.Method.Invoke(
			dlg.Target, 
			new object[] 
			{ 
			  source,
			  args 
			});
                }
                doIfChanged();
            }
        }

Now you can use a strongly typed NotifyPropertyChanged declaration without using your base class

    public class PersonStaticReflection : INotifyPropertyChanged
    {
        private string _firstName;
        private string _lastName;
        public string FirstName
        {
            get { return _firstName; }
            set { this.SetProperty(
			() => FirstName, 
			() => _firstName, 
			value); 
		}
        }
        public string LastName
        {
            get { return _lastName; }
            set
            {
                this.SetProperty(() => LastName,
                                 () => _lastName,
                                 value,
                                 () =>
                                     {
		// do something useful here
                                     });
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

For those concerned, you can statically cache the PropertyChanged field in a dictionary mapped to the object type so that you only have to reflect on it one time.

Published Monday, February 23, 2009 1:19 PM by Mike Brown

Comments

# re: Static Reflection: Say What?

I totally love the use of expression trees.  Way to keep it DRY.

Tuesday, February 24, 2009 5:34 AM by David Justice

# re: Static Reflection: Say What?

Unfortunately this doesn't work if the backing variable has a private setter.

Thursday, September 10, 2009 3:51 AM by Patrick

# re: Static Reflection: Say What?

Why not? the closure happens in the context of the owning class.

Wednesday, September 30, 2009 5:46 PM by Mike Brown

Leave a Comment

(required) 
(required) 
(optional)
(required)