Something I’ve struggled with in the past with C# is anonymous functions. Its one of those “how can you call yourself a professional if you don’t understand this?” kind of things.
Conceptually, I understand them. Its a function, without a name. But actually implementing with them has been a struggle that I usually end up going around. Something about saying
x => x.doSomeStuff() inside the arguments to another function. What is x, how does the compiler know, wtf? This is particuarly uneasing because I used them all the time in ASP.NET views. Here’s one of the signatures for
TextBoxFor<TModel, TProperty>(HtmlHelper<TModel>, Expression<Func<TModel, TProperty>>, IDictionary<String, Object>)
Expression<Func<TModel, TProperty>>… huuuuuuuuh?
But not today. Today I figured it out.
The problem was simple: validate a string before passing it off to another system. The string has to be only letters, numbers, or spaces.
The first version was without spaces but then I found out I needed to handle spaces. This was easy to do with the help of intellisense, I did it without really getting what was going on.
if(! filterThisString.All(c => char.IsLetterOrDigit(c)))
Then I had to add the filter for spaces, and I tried too hard. Exactly none of this code made any sense and the compiler was happy to inform me of such.
if(! filterThisString.All(new Func<char,bool> => () char.IsLetterOrDigit || char.Equals(' ')
So then I figured that if I wanted to write my own
func I was just going to have to declare it outside of the function.
Func<char, bool> isValidCharacter = c => char.IsLetterOrDigit(c) || c.Equals(' '); if(! filterThisString.All(isValidCharacter))
That works, yay! I wrote a
Func, but its not anonymous. It has a name.
Then the ‘aha’ moment came when I took another stab at one-lining it. I don’t need any of the signature when using an anonymous function. The compiler figures it out for you! That’s why you just need to declare a reference to what you want to manipulate. Now it all clicks.
if(! filterThisString.All(c => char.IsLetterOrDigit(c) || c.Equals(' ')))