user5126784
user5126784

Reputation:

Generic Extension Methods with Template Method

I have an abstract class named OptionalParameters to be a base class for other parameter classes.

public abstract class OptionalParameter
{
    //Template Method 
    public string GenerateQueryString()
    {
        return OptionalParameterExtensions.GenerateQueryStringWithParameters<OptionalParameter>(this);
    }
}

And I have a base class as OptionalParameter. TimeEntriesParameters inherits from that base class.

public class TimeEntriesParameters : OptionalParameter
{
//Some Properties
}

So i want to generate a query string with my inherited classes properties. Then i wrote an extension method for that purpose.

public static class OptionalParameterExtensions
{
    public static string GenerateQueryStringWithParameters<T>(this T optionalParameters) where T : OptionalParameter
    {
        //Generates and returns query string with properties of T type
    }
}

After applying the structure stated above for the classes that inherits from base class with a usage stated below.

TimeEntriesParameters parameters = new TimeEntriesParameters();
string queryString = parameters.GenerateQueryString();

How can I create a generic template method for every OptionalParameter

EDIT: My real purpose is to read classes properties as below and then return a string like "?page=1&fromDate=20150728" etc.

public class TimeEntriesParameters : OptionalParameter
{
    [EntityOptionalParameter(ParameterName="page")]
    public int Page { get; set; }

    [EntityOptionalParameter(ParameterName = "fromDate")]
    public DateTime FromDate { get; set; }

    [EntityOptionalParameter(ParameterName = "fromTime")]
    public DateTime FromTime { get; set; }

    [EntityOptionalParameter(ParameterName = "ToDate")]
    public DateTime ToDate { get; set; }

    [EntityOptionalParameter(ParameterName = "ToTime")]
    public DateTime ToTime { get; set; }

    [EntityOptionalParameter(ParameterName = "SortOrder")]
    public Enumerations.SortOrder SortOrder { get; set; }

    [EntityOptionalParameter(ParameterName = "UserId")]
    public int UserId { get; set; }
}

So i didn't want to write a method for every class to generate query string. I think I can put a template method in OptionalParameter base class and create the string by the class properties types and attribute properties.

Upvotes: 0

Views: 371

Answers (1)

Fernando Matsumoto
Fernando Matsumoto

Reputation: 2717

The type parameter in GenerateQueryStringWithParameters<T>() is useless, since you're always calling the method as the type parameter OptionalParameter. You can therefore rewrite the method as GenerateQueryStringWithParameters(this OptionalParemeter optionalParameter).

In order to generate the query string, you need to use reflection to loop through the properties in the class of optionalParameter and check if they have an EntityOptionalParameter. Assuming you can access the ParameterName through the property EntityOptionalParameter.ParameterName, you can do the following:

public static string GenerateQueryStringWithParameters(this OptionalParameter optionalParameter)
{
    var props = optionalParameter.GetType().GetProperties()
        .Select(x => new { Prop = x, Attr = x.GetCustomAttribute<EntityOptionalParameter>() })
        .Where(x => x.Attr != null); // Get all properties that have the attribute

    var sb = new StringBuilder("?");
    var first = true;
    foreach(var prop in props) // Loop through properties
    {
        if (first)
        {
            first = false;
        }
        else
        {
            sb.Append("&")
        }
        sb.Append(prop.Attr.ParameterName); // Append property name
        sb.Append("=");
        sb.Append(prop.Prop.GetValue(optionalParameter)); // Append property value
    }
    return sb.ToString()
}

Upvotes: 1

Related Questions