Click here to Skip to main content
15,867,870 members
Articles / Programming Languages / C#

(5) Interesting Uses of Linq.Expression

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
24 Jan 2012CPOL2 min read 13.1K   7  
Listed here are 5 interesting uses of Linq.Expression without writing a LinqToSomething provider, of course.

… without writing a LinqToSomething provider, of course. The Expression.<Func<T>> construction is sometimes a little frightening since we are supposed to have to write some complex tree navigation in order to achieve the expression behavior, but this is not always true. There are scenarios in which we can use it without any complex tree visit. In this post, we will see some real world examples using this strategy.

1) INotifyPropertyChanged Without “Magic Strings”

This interface is implemented in its simplest form:

C#
public string CustomerName
        {
            get
            {
               return this.customerNameValue;
            }
            set
            {
               if (value != this.customerNameValue)
               {
                   this.customerNameValue = value;
                   NotifyPropertyChanged("CustomerName");
               }
           }
       }

We can leverage Linq.Expression here by this simple base class:

C#
class PropertyChangeBase : INotifyPropertyChanged
    {
        protected void SignalChanged<T>(Expression<Func<T>> exp)
        {
            if (exp.Body.NodeType == ExpressionType.MemberAccess)
            {
                var name = (exp.Body as MemberExpression).Member.Name;
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
           else
               throw new Exception("Unexpected expression");
       }
       #region INotifyPropertyChanged Members
       public event PropertyChangedEventHandler PropertyChanged = delegate { };
       #endregion
   }

By deriving our class from this one, we can easily notify a property change by writing:

C#
SignalChanged(()=>CustomerName);

This allows us to leverage intellisense, and it is refactoring friendly, so we can change the name of our property without pain. The first project I saw using this technique was Caliburn Micro, but I’m not sure it is the only one and the first. The same technique is used here to test the INotifyPropertyChange behavior.

2) Argument Verification

Really similar to the problem above, we want to avoid:

C#
static int DivideByTwo(int num)
  {
      // If num is an odd number, throw an ArgumentException.
      if ((num & 1) == 1)
          throw new ArgumentException("Number must be even", "num");
      // num is even, return half of its value.
      return num / 2;
  }

In this case, we are typing NUM, that is the name of the argument, as a literal string which is bad. We would preferably write something like this:

C#
public void DoSomething(int arg1) 
    { Contract.Expect(() => arg1).IsGreatherThan(0) .IsLessThan(100); ; } 

That again gives us intellisense and refactoring awareness. You can find the code for this helper class here, and a brief description in this post.

3) The MoQ Mocking Library

The MoQ library is a .NET library for creating mock objects easily to use that internally leverage Linq.Expression to achieve such a readable syntax:

C#
mock.Setup(framework => framework.DownloadExists("2.0.0.0"))
    .Returns(true)
    .AtMostOnce();

4) A Generic Swap Function

The simplest way to create a generic Swap function in C# is:

C#
void Swap<T>(ref T a, ref T b)
{
   T temp = a;
   a = b;
   b = temp;
}

Unfortunately, this won’t work if we want to swap two properties of an object, or two elements of an array. We would like to write something like this:

C#
var t = new Test_() { X = 0, Y = 1 };
Swapper.Swap(() => t.X, () => t.Y);
Assert.AreEqual(0, t.Y);
Assert.AreEqual(1, t.X);

or for arrays:

C#
int[] array = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Swapper.Swap(() => array[0], () => array[1]);
Assert.AreEqual(2, array[0]);
Assert.AreEqual(1, array[1]);

We can achieve this by a simple helper class using Linq.Expression:

C#
public class Swapper
    {
        public static void Swap<T>(Expression<Func<T>> left, Expression<Func<T>> right)
        {
            var lvalue = left.Compile()();
            var rvalue = right.Compile()();
            switch (left.Body.NodeType)
            {
               case ExpressionType.ArrayIndex:
                   var binaryExp = left.Body as BinaryExpression;
                   AssignTo(rvalue, binaryExp);
                   break;

               case ExpressionType.Call:
                   var methodCall = left.Body as MethodCallExpression;
                   AssignTo(rvalue, methodCall);
                   break;

               default:
                   AssignTo(left, rvalue);
                   break;
           }

           switch (right.Body.NodeType)
           {
               case ExpressionType.ArrayIndex:
                   var binaryExp = right.Body as BinaryExpression;
                   AssignTo(lvalue, binaryExp);
                   break;

               case ExpressionType.Call:
                   var methodCall = right.Body as MethodCallExpression;
                   AssignTo(lvalue, methodCall);
                   break;

               default:
                   AssignTo(right, lvalue);
                   break;
           }
       }

       private static void AssignTo<T>(T value, MethodCallExpression methodCall)
       {
           var setter = GetSetMethodInfo
        (methodCall.Method.DeclaringType,methodCall.Method.Name);
           Expression.Lambda<Action>(
               Expression.Call(methodCall.Object, setter, 
               Join(methodCall.Arguments, Expression.Constant(value)))
           ).Compile()();
       }

       private static Expression[] Join(ReadOnlyCollection<Expression> args,Expression exp)
       {
           List<Expression> exps = new List<Expression>();
           exps.AddRange(args);
           exps.Add(exp);
           return exps.ToArray();
       }

       private static MethodInfo GetSetMethodInfo(Type target, string name)
       {
           var setName = Regex.Replace(name, "get", new MatchEvaluator((m) =>
           {
               return m.Value.StartsWith("g")?"set":"Set";
           })
           ,RegexOptions.IgnoreCase);
           var setter = target.GetMethod(setName);
           if (null == setter)
           {
               throw new Exception("can't find an expected method named:" + setName);
           }
           return setter;
       }

       private static void AssignTo<T>(Expression<Func<T>> left, T value)
       {
           Expression.Lambda<Func<T>>(Expression.Assign
           (left.Body, Expression.Constant(value))).Compile()();
       }
       private static void AssignTo<T>(T value, BinaryExpression binaryExp)
       {
           Expression.Lambda<Func<T>>(Expression.Assign
           (Expression.ArrayAccess(binaryExp.Left, binaryExp.Right), 
           Expression.Constant(value))).Compile()();
       }
   }

This code leverages a sample by Takeshi Kiriya, I just added the ability in handling array to his own in the original code.

5) Unit Testing the Presence of An Attribute

Thomas Ardal talks in this post about how to easily unit test the presence of an attribute on a method of a class, useful for example in MVC scenarios, or in other AOP circumstances.

A test leveraging his strategy is written as below:

C#
var controller = new HomeController();
controller.ShouldHave(x => x.Index(), typeof(AuthorizeAttribute));

So we show five different simple applications, I hope you find some inspiration here for your work, and feel free to write about your own ideas and enrich the list.


License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Italy Italy
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --