Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to refactor these functions which have one line difference

Tags:

c#

I have 3 functions where the only difference in is the values I point out with comment

//-- point of difference

The majority of the function is the same across all three. The "DRY" factor is haunting my sleep :). I was wondering; can these could be merged easily and readably?

I have had situations like this before and I am hoping to learn something here.

private string RenderRequestType(string render, NameValueCollection nvp, string prefix, string regexWild, string suffix)
{
    string regex = prefix + regexWild + suffix;

    MatchCollection matches = Regex.Matches(render, regex);

    foreach (Match match in matches)
    {
        foreach (Capture capture in match.Captures)
        {
            string name = capture.Value.Replace(prefix, "", StringComparison.CurrentCultureIgnoreCase).Replace(suffix, "", StringComparison.CurrentCultureIgnoreCase);

            //-- point of difference
            string value = nvp[name];

            render = render.Replace(capture.Value, value);
        }
    }

    return render;
}

private string RenderSessionType(string render, HttpContext httpContext, string prefix, string regexWild, string suffix)
{
    string regex = prefix + regexWild + suffix;

    MatchCollection matches = Regex.Matches(render, regex);

    foreach (Match match in matches)
    {
        foreach (Capture capture in match.Captures)
        {
            string name = capture.Value.Replace(prefix, "", StringComparison.CurrentCultureIgnoreCase).Replace(suffix, "", StringComparison.CurrentCultureIgnoreCase);

            //-- point of difference
            object session = httpContext.Session[name];
            string value = (session != null ? session.ToString() : "");

            render = render.Replace(capture.Value, value);
        }
    }

    return render;
}

private string RenderCookieType(string render, HttpContext httpContext, string prefix, string regexWild, string suffix)
{
    string regex = prefix + regexWild + suffix;

    MatchCollection matches = Regex.Matches(render, regex);

    foreach (Match match in matches)
    {
        foreach (Capture capture in match.Captures)
        {
            string name = capture.Value.Replace(prefix, "", StringComparison.CurrentCultureIgnoreCase).Replace(suffix, "", StringComparison.CurrentCultureIgnoreCase);

            //-- point of difference
            HttpCookie cookie = httpContext.Request.Cookies[name];
            string value = (cookie != null ? cookie.Value : "");

            render = render.Replace(capture.Value, value);
        }
    }

    return render;
}
like image 494
Valamas Avatar asked Feb 02 '11 22:02

Valamas


People also ask

What is function refactoring?

Refactoring is the process of restructuring code, while not changing its original functionality. The goal of refactoring is to improve internal code by making many small changes without altering the code's external behavior.

Can a function only be used once?

It's fine to have a function even if only used once. Blocks of code should ideally only do one thing, perform one computation, one calculation. This makes it easy to work on the flow of your logic, instead of getting bogged down with huge blocks of code.

How many lines should a method have?

a) Methods should not have more than an average of 30 code lines (not counting line spaces and comments).

Should you always refactor?

The best time to consider refactoring is before adding any updates or new features to existing code. Going back and cleaning up the current code before adding in new programming will not only improve the quality of the product itself, it will make it easier for future developers to build on the original code.


2 Answers

You could modify the function to take a Func<string, string> to do the lookup:

private string RenderType(string render, Func<string, string> lookupFunc, string prefix, string regexWild, string suffix)
{
    string regex = prefix + regexWild + suffix;

    MatchCollection matches = Regex.Matches(render, regex);

    foreach (Match match in matches)
    {
        foreach (Capture capture in match.Captures)
        {
            string name = capture.Value.Replace(prefix, "", StringComparison.CurrentCultureIgnoreCase).Replace(suffix, "", StringComparison.CurrentCultureIgnoreCase);

            //-- point of difference
            string value = lookupFunc(name);

            render = render.Replace(capture.Value, value);
        }
    }

    return render;
}

Then write your functions in terms of this one, e.g.:

private string RenderRequestType(string render, NameValueCollection nvp, string prefix, string regexWild, string suffix)
{
    return RenderType(render, name => nvp[name], prefix, regexWild, suffix);
}
like image 100
Lee Avatar answered Sep 21 '22 23:09

Lee


Pass in a Func<string, string> to get the value associated with a given name. In the first case that would just use nvp's indexer; in the second it would use the session. You could either use separate methods to create the delegates, or lambda expressions. (I'd definitely use a lambda expression for the first one; I might use a separate method for the second.)

like image 22
Jon Skeet Avatar answered Sep 23 '22 23:09

Jon Skeet