HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Returning a more specific class

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
classreturningspecificmore

Problem

I would appreciate some feedback on my design of a few classes to query the Trakt.tv API.

public abstract class TraktQuery
{
    private const string baseUrl = "http://api.trakt.tv/";
    private const string apiKey = "[API key here]";

    protected abstract string QueryUrl { get; }
    protected abstract List QueryParameters { get; }
    protected abstract TraktResponse ParseResponse(string response);

    public TraktResponse PerformQuery()
    {
        //exception handling removed for brevity
        WebClient webClient = new WebClient();
        string url = baseUrl + QueryUrl + "/" + apiKey + "/" + string.Join("/", QueryParameters);
        string response = webClient.DownloadString(url);
        return ParseResponse(response);
    }
}

public class TraktQueryEpisodeSummary : TraktQuery
{
    private string _showName;
    private int _season;
    private int _episodeNumber;

    public TraktQueryEpisodeSummary(string showName, int season, int episodeNumber)
    {
        _showName = showName;
        _season = season;
        _episodeNumber = episodeNumber;
    }

    protected override string QueryUrl
    {
        get { return "show/episode/summary.json"; }
    }

    protected override List QueryParameters
    {
        get
        {
            List paramters = new List();
            paramters.Add(_showName);
            paramters.Add("" + _season);
            paramters.Add("" + _episodeNumber);
            return paramters;
        }
    }

    protected override TraktResponse ParseResponse(string response)
    {
        return JsonConvert.DeserializeObject(response);
    }

public class TraktResponseEpisodeSummary : TraktResponse
{
    public TraktShowInformation show { get; set; }
    public TraktEpisode episode { get; set; }
}


Currently TraktResponse is an empty abstract class but I'll probably add to it soon.

This code is then used as follows:

```
class Program
{
static void Main(string[] args)
{

TraktQueryEpisodeSum

Solution

Dreza has outlined the correct approach (the same used in IComparable). You can make your class generic, with a type constraint:

public abstract class TraktQuery where TResponse : TraktResponse


And change every occurence of TraktResponse to TResponse:

protected abstract TResponse ParseResponse(string response);


and

public TResponse PerformQuery()
{
    //...
}


Then, your deriving class can be defined as

public class TraktQueryEpisodeSummary : TraktQuery
{
    //...
    protected override TraktResponseEpisodeSummary ParseResponse(string response)
    {
        //...
    }
    //...
}


Voila, no cast necessary:

TraktResponseEpisodeSummary summary = query.PerformQuery();


Further suggestions:

-
Use collection and object initializers, for instance in the overridden QueryParameters:

return new List {_showName, _season.ToString(), _episodeNumber.ToString()};


-
Or turn them into an IEnumerable and use an iterator block:

protected override IEnumerable QueryParameters
{
    get
    {
        yield return _showName;
        yield return _season.ToString();
        yield return _episodeNumber.ToString();
    }
}


-
Be careful when concatenating strings to form a URL like this:

string url = baseUrl + QueryUrl + "/" + apiKey + "/" + string.Join("/",QueryParameters);


It might be better to

  • Use the Uri and/or UriBuilder class



  • Put the first three parts into an sequence, then call IEnumerable.Concat and finally string.Join



  • There's probably some even better options.

Code Snippets

public abstract class TraktQuery<TResponse> where TResponse : TraktResponse
protected abstract TResponse ParseResponse(string response);
public TResponse PerformQuery()
{
    //...
}
public class TraktQueryEpisodeSummary : TraktQuery<TraktResponseEpisodeSummary>
{
    //...
    protected override TraktResponseEpisodeSummary ParseResponse(string response)
    {
        //...
    }
    //...
}
TraktResponseEpisodeSummary summary = query.PerformQuery();

Context

StackExchange Code Review Q#18190, answer score: 3

Revisions (0)

No revisions yet.