Do you have a blind spot in programming?
I mean is there a common technique or language feature that you can't really get used to.
Well, I have one (or probably more than one) and mine is usage of delegate
.
Hands up! Who else doesn't feel comfortable with delegates? Be honest!
So what's a delegate?
Since my courses at university introduced me to C, I know about function pointers. Function pointers are handy if you want to pass methods as arguments. So in my mind a delegate is something like a function pointer. Eureka! I got it. I have not!
A concrete scenario?
I would like to remove any line from a text file that matches a regular expression.
Assuming I have a collection of lines, List<T>
has method RemoveAll
which seems to be perfectly suitable for that purpose.
RemoveAll
expects an evaluation method as argument for deciding on whether to remove or leave a list element.
And there it is: The function pointer!
Any code here?
public static int RemoveLinesFromFile(string path, string pattern)
{
List<string> lines = new List<string>(File.ReadAllLines(path));
int result = lines.RemoveAll(DoesLineMatch);
File.WriteAllLines(path, lines.ToArray());
return result;
}
So I'm looking for a function DoesLineMatch
which evaluates if a line matches a pattern.
Do you see the problem?
RemoveAll
expects a delegate Predicate<string> match
as argument.
I would have coded it like this:
private static bool DoesLineMatch(string line, string pattern)
{
return Regex.IsMatch(line, pattern);
}
But then I'm getting an error "Expected a method with 'bool DoesLineMatch(string)' signature". What am I missing here?
Does it work at all?
This is how I finally got it working:
public static int RemoveLinesFromFile(string path, string pattern)
{
List<string> lines = new List<string>(File.ReadAllLines(path));
int result = lines.RemoveAll(delegate(string line)
{
return Regex.IsMatch(line, pattern);
});
File.WriteAllLines(path, lines.ToArray());
return result;
}
I'm happy that it works but I don't understand it.
And what is the question?
What I did to get it working is simply inlining the method. As far as I understand inlining, it is just some kind of use-once-and-destroy-code. If you use a variable or method only once you may inline it, but inlining is always equivalent to declaring it explicitly.
Is there a way to declare the method explicitly? How would I do it?
PS.: Pardon me that my question is somewhat lengthy.
PPS.: As soon as I get this delegate thing I will make the leap from 2.0 to 3.0 and learn lambdas.
PPPS.: Following Jon's hint on efficiency of Regex.IsMatch(string, string)
I modified my code:
int result = lines.RemoveAll(delegate(string line)
{
Regex regex = new Regex(pattern);
return regex.IsMatch(line);
});
That isn't of much help regarding efficiency matters. So I followed ReSharper's proposal and moved the Regex instantiation to the outer scope:
Regex regex = new Regex(pattern);
int result = lines.RemoveAll(delegate(string line)
{
return regex.IsMatch(line);
});
Now ReSharper urged me to replace this with a method group:
Regex regex = new Regex(pattern);
int result = lines.RemoveAll(regex.IsMatch);
And that is quite similar to the answers proposed here. Not what I asked for, but again I'm amazed how ReSharper (and Stack Overflow of course) helps learning.