| Kian Ryan ( @ 2008-05-29 23:11:00 |
| Current music: | La Cenerentola - Carlo Maria Giulini |
Cock-up of the day...
Given the following code, what would you expect tagList to contain at the end of this sequence?
string tagString = "First, Post, Please"; ListtagList = new List (tagString.Split(',')); tagList.ForEach( delegate(string t){ t = t.Trim().ToLower(); });
For those who said {"first","post","please"} go to the back of the class. Let's go back to lesson one shall we?
Strings are classes, yes?
Good.
But they're not normal classes. They are immutable classes. What's so special about immutable classes? Every time you muck around with them, there's a new copy of them generated on the stack and the old one is simply thrown away. Added to that, ForEach passes byval rather than byref, so even if we switched from string to int or any other primitive type, we're still in trouble.
This is a good thing, since it reduces some significant headaches when it comes to concurrency. However, it does mean that when you do what you *think* are nice little tricks such as the above, in fact what is happening is a new copy of the string is created, a new copy is then created after it's manipulated, and then thrown away before moving onto the next one.
The answer lies in another extension method - ConvertAll. So our line above now becomes:
tagList.ConvertAll( delegate(string t){ t = t.Trim().ToLower(); });
Even better, if we're working in C# 3.0, we can also take advantage of the new lambda notation (a quick Hi to all the Haskell people who suddenly raise their heads) and we can now get:
tagList.ConvertAll( t => t.Trim().ToLower(); );
Now *that* is elegant.