I had a method that looked like this in my code:
public string Translate(string entity, string field)
{
string key = Translator.GetKey(entity, field);
if (translationCache.ContainsKey(key))
return translationCache[key];
else
{
string res = this.Translator.Translate(entity, field);
translationCache.Add(key, res);
return res;
}
}
This code uses a cache mechanism that counts for most of the lines in the method. For a new requirement I needed to add an overloaded method that takes a single argument and calls an overloaded versions of Translator.GetKey and Translator.Translate methods, but the rest of the code would look the same. Of course I would like to keep the code DRY (Don’t Repeat Yourself). So how do you solve a problem when a single line of code in the middle of the method needs to be different, but the rest should be the same? Of course you could split the logic and create a couple of smaller methods that handles other parts of the code, but in this case it is hard to do that in a good way. Typically I would say that this code will be copied and pasted and then changing the line that needs to, but violating DRY. The way I solved the problem was to use a delegate as argument and invoke that on the line that differs. In this case I choose the Func<T>() delegate.
public string Translate(string name)
{
return Translate(Translator.GetKey(name), () => this.Translator.Translate(name));
}
public string Translate(string entity, string field)
{
return Translate(Translator.GetKey(entity, field), () => this.Translator.Translate(entity, field));
}
private string Translate(string key, Func<string> translation)
{
if (translationCache.ContainsKey(key))
return translationCache[key];
else
{
string res = translation.Invoke();
translationCache.Add(key, res);
return res;
}
}
Now I have a single private method that handles the caching part except for creating the key. The solution with taking the Func<string> delegate as a parameter is easily called by a using lambda expression in the public methods. Each expression calls the correct overloaded version of the Translate method.
Hope this helps you to find new ways to keep your code DRY, when extracting methods and other techniques, doesn’t fit that well.