Using .Net 3.x Lambda Expressions to Write More Concise Code

Lambda Expressions via msdn.com:

A lambda expression is an anonymous function that can contain expressions and statements, and can be used to create delegates or expression tree types. All lambda expressions use the lambda operator =>, which is read as “goes to”. The left side of the lambda operator specifies the input parameters (if any) and the right side holds the expression or statement block. The lambda expression x => x * x is read “x goes to x times x.”

> more

Overview of Lambda Expressions

One of the new .NET 3.x language features that we have been enjoying recently is Lambda Expressions. These expressions are essentially the next iteration of the anonymous methods that were offered with .NET 2.0, with one of the major differences being the simplicity with which you can construct inline methods. When used appropriately, these Lambda Expressions let us get more done with less code and less redundancy.

Lambda Expressions In Practice

Let’s say you run into a situation in which you want to write a method that takes as an argument an object of a particular type and a property on the object you want to work with. For example if we take the example below and want to make the redundant parts (in blue text) a shared method, except the different property (in red text) being used is potentially holding us up. (Continue reading for example code).

public class MyClass
{
public string FilePath1;
public string FilePath2;

public void Save()
{
this.LastSaved = DateTime.Now;
// saves it somewhere, such as a database.
}

public DateTime LastSaved;
}

public class BusinessLogicClass
{
private bool deleteProperty1 = false;
private bool deleteProperty2 = true;

public string DoSomething(string PropertyValue)
{
/* does something*/
return PropertyValue + PropertyValue;
}

public void BindDataObject(MyClass MyInstance)
{
// binds the instance of MyClass to, let’s say the display fields on the page.
// and let’s say it to be called whenever MyInstance gets Saved because it
// displays the LastSavedDate.
}

public void MainCode(MyClass MyInstance)
{
// MyInstance.Property1 = “hello.xls”;
// MyInstance.Property2 = “world.xls”;
if (this.deleteProperty1)
{
string oldFilePath = MyInstance.FilePath1;
if (File.Exists(MyInstance.FilePath1))
{
File.Delete(MyInstance.FilePath1);
MyInstance.FilePath1 = “”;
MyInstance.Save();
this.BindDataObject(MyInstance);
this.ShowDeletedFeedbackMessage(MyInstance, oldFilePath);
}
else
{
MyInstance.FilePath1 = “”;
MyInstance.Save();
this.BindDataObject(MyInstance);
this.ShowFileDoesNotExistFeedbackMessage(MyInstance, oldFilePath);
}
}

if (this.deleteProperty2)
{
string oldFilePath = MyInstance.FilePath2;
if (File.Exists(MyInstance.FilePath2))
{
File.Delete(MyInstance.FilePath2);
MyInstance.FilePath2 = “”;
MyInstance.Save();
this.BindDataObject(MyInstance);
this.ShowDeletedFeedbackMessage(MyInstance, oldFilePath);
}
else
{
MyInstance.FilePath2 = “”;
MyInstance.Save();
this.BindDataObject(MyInstance);
this.ShowFileDoesNotExistFeedbackMessage(MyInstance, oldFilePath);
}
}
}
}

And let’s say, for argument’s sake, that one can’t think of good way around the difference other than some mechanism to pass in some type of wrapper to the property as argument for their method. In .Net 1.x, this was already available via the PropertyInfo object, and the code probably would have gone something like this:

public void MainCode (MyClass MyInstance)
{
// MyInstance.Property1 = “hello.xls”;
// MyInstance.Property2 = “world.xls”;
if (this.deleteProperty1)
this. DeleteFile(MyInstance, “FilePath1”);

if (this.deleteProperty2)
this. DeleteFile(MyInstance, “FilePath2”);
}

protected void DeleteFile(MyClass MyInstance, string PropertyName)
{
PropertyInfo fileProperty = MyInstance.GetType().GetProperty(PropertyName);
string oldFilePath = (string) fileProperty.GetValue(MyInstance, null);
if (File.Exists(oldFilePath))
{
File.Delete(oldFilePath);
fileProperty.SetValue(MyInstance, “”, null);
MyInstance.Save();
this.BindDataObject(MyInstance);
this.ShowDeletedFeedbackMessage(MyInstance, oldFilePath);
}
else
{
fileProperty.SetValue(MyInstance, “”, null);
MyInstance.Save();
this.BindDataObject(MyInstance);
this.ShowFileDoesNotExistFeedbackMessage(MyInstance, oldFilePath);
}
}

Not a bad improvement. All we had to do was pass in a string of the name of the property we were concerned about. However, we lost the type-checking on the class, the property, and a compile-time check if the class even had a property of the string we passed in. The last one being very problematic when it comes to typos or if we decide to later change the property name.
Now if we pause to think about it, in the case above, getting a property is very much like a method with the signature string GetFilePath(MyClass MyInstance) and setting a property very much like a method with a signature void SetFilePath(MyClass MyInstance, string FilePath). So maybe we can use delegates instead of the PropertyInfo for passing in the information. Unfortunately passing in anonymous delegates were somewhat clunky in terms of syntax in .Net 2.0. Now with .Net 3.5, we should hopefully be able to do so more easily with lambda expressions. Instead of having to create what might start to feel like superfluous delegate types, we’ll use the .Net built in delegate types Func< MyClass, string > (available now in .Net 3.x) for the Get and Action<MyClass, string> (available since .Net 2.0) for the Set.

public void MainCodeRewrite (MyClass MyInstance)
{
// MyInstance.Property1 = “hello.xls”;
// MyInstance.Property2 = “world.xls”;
if (this.deleteProperty1)
this.DeleteFile ( MyInstance,
myClass => myClass.FilePath1,
(myClass, filePath) => myClass.FilePath1 = filePath);

if (this.deleteProperty2)
this.DeleteFile ( MyInstance,
myClass => myClass.FilePath2,
(myClass, filePath) => myClass.FilePath2 = filePath);
}

protected void DeleteFile (MyClass MyInstance,
Func<MyClass, string> GetProperty,
Action<MyClass, string> SetProperty)
{
string oldFilePath = GetProperty(MyInstance);
if (File.Exists(oldFilePath))
{
File.Delete(oldFilePath);
SetProperty(MyInstance, “”);
MyInstance.Save();
this.BindDataObject(MyInstance);
this.ShowDeletedFeedbackMessage(MyInstance, oldFilePath);
}
else
{
SetProperty(MyInstance, “”);
MyInstance.Save();
this.BindDataObject(MyInstance);
this.ShowFileDoesNotExistFeedbackMessage(MyInstance, oldFilePath);
}
}

Hmmm… Well, using lambda expressions did turn out less clunky than the old .Net 2.0 syntax (see below), but still more clunky than passing a simple, single string of the property name.

// .Net 2.0 version of passing in anonymous delegates
this.DeleteFile (MyInstance,
delegate(MyClass myClass) { return myClass.FilePath1; },
delegate(MyClass myClass, string FilePath) { myClass.FilePath1 = FilePath; });

So we’ll count the extra clunkiness as a con. However, we got back compile-time type-checking and checking that the class actually has said property. On the downside, and this might be due to not wanting to create new delegate types, but we’re now passing in two delegates that are logically coupled and have a more specific abstract meaning than just what their signatures would indicate (Func<MyClass, string> could be intended to be a lot of things, not just a property wrapper). While the called method signature might hint that those arguments are meant to be simple wrappers to the same property (and the method documentation could also explicitly say so), the person eye-balling just MainCodeRewrite won’t immediately or necessarily see that and could be scratching their heads at what these nameless lambda expressions are supposed to be and not be one hundred percent confident that they’re related to each other. This would also get exasperated if there are more than one properties in a scenario (though, I off the top of my head, I would have to imagine if your method has more than two properties as parameters, my gut feeling would be to re-examine if it’s getting too complicated).
So as a possible solution to this ambiguity issue, we could introduce a class. For the sake of properties, we’re really only concerned with it having a Get and a Set method (I’ll just call them Get and Set, rather than mimic PropertyInfo’s convention of GetValue and SetValue since those are the only two methods/properties I’m putting on the object.).

public class PropertyWrapper<TClass, TProperty>
{
public PropertyWrapper() { }

public PropertyWrapper( Func<TClass, TProperty> GetMethod, Action<TClass, TProperty> SetMethod)
{
this.Initialize(GetMethod, SetMethod);
}

public void Initialize( Func<TClass, TProperty> GetMethod, Action<TClass, TProperty> SetMethod)
{
this.getMethod = GetMethod;
this.setMethod = SetMethod;
}

public virtual TProperty Get(TClass Instance)
{
return this.getMethod(Instance);
}

public virtual void Set(TClass Instance, TProperty PropertyValue)
{
this.setMethod(Instance, PropertyValue);
}

private Func<TClass, TProperty> getMethod;
private Action<TClass, TProperty> setMethod;
}
This is roughly how it would go using that class.
public void MainCode (MyClass MyInstance)
{
// MyInstance.Property1 = “hello.xls”;
// MyInstance.Property2 = “world.xls”;
if (this.deleteProperty1)
{
PropertyWrapper<MyClass, string> filePath1Property = new PropertyWrapper<MyClass, string>(
myClass => myClass.FilePath1,
(myClass, filePath) => myClass.FilePath1 = filePath);
this.DeleteFile (MyInstance, filePath1Property);
}

if (this.deleteProperty2)
{
PropertyWrapper<MyClass, string> filePath2Property = new PropertyWrapper<MyClass, string>(
myClass => myClass.FilePath2,
(myClass, filePath) => myClass.FilePath2 = filePath);
this.DeleteFile (MyInstance, filePath2Property);
}
}

protected void DeleteFile (MyClass MyInstance,
IPropertyWrapper<MyClass, string> FilePathProperty)
{
string oldFilePath = FilePathProperty.Get(MyInstance);
if (File.Exists(oldFilePath))
{
File.Delete(oldFilePath);
FilePathProperty.Set(MyInstance, “”);
MyInstance.Save();
this.BindDataObject(MyInstance);
this.ShowDeletedFeedbackMessage(MyInstance, oldFilePath);
}
else
{
FilePathProperty.Set(MyInstance, “”);
MyInstance.Save();
this.BindDataObject(MyInstance);
this.ShowFileDoesNotExistFeedbackMessage(MyInstance, oldFilePath);
}
}

So… the new class introduces some more clunkiness, but the calling code is now more intuitively readable. The gains seem less obvious than the jump from PropertyInfo to delegates, but is more of my preference after giving both a test run. I also originally used an interface so my ability to wrap properties wouldn’t be tied to this delegate strategy, along with a few other things that I won’t go into, to help give me flexibility on which strategies seemed most useful given a situation.

« Prev Article
Next Article »