Question

I want to get statistics information from some sort of storage. Since I want to be able to switch storage I would like to use an interface and program towards it.

There are some requirements that I need to put on the implementations though, such as only accepting a certain range of strings. I am not sure how to accomplish this in a nice way. I currenctly have an interface specifying the methods. I also have an abstract class that implements the interface and is validating the string value in its constructor. I am curious if my current setup is good or if there are better ways of doing it. Below is a code sample.

public interface IStaticsRepository
{
    int GetApiStatistics(string apiId);
}

public abstract class StatisticsReposity : IStatisticsRepository
{
    public readonly ICollection<string> ValidTimeUnits = new[] { "hour", "day" };

    public StatisticsRepository(string timeUnit)
    {
        if (string.IsNullOrWhiteSpace(timeUnit))
        {
            throw new ArgumentNullException("timeUnit");
        }

        if (!ValidTimeUnits.Contains(timeUnit))
        {
            throw new ArgumentException("Now a valid time unit.", "timeUnit");
        }

        public abstract int GetApiStatistics(string apiId);
    }

    public class MongoDbStatisticsRepository : StatisticsRepository
    {
        public MongoDbStatisticsRepository(string timeUnit)
            : base(timeUnit)
        { }

        public override int GetApiStatistics(string apiId)
        { }
    }
Was it helpful?

Solution

Static typing is your friend here. If you need a string backed type for whatever reason, as opposed to using enums which are int backed, I've used a pattern like the following:

public class TimeUnit
{
  private readonly string _unit;

  private TimeUnit(string unit)
  {
    _unit = unit;
  }

  public static readonly TimeUnit Hour = new TimeUnit("hour");
  public static readonly TimeUnit Day = new TimeUnit("day");
  public string ToString()
  {
    return _unit;
  }
}

With this, you still have access to the backing string, assuming the rest of your code relies on that, but you're also forcing clients to either pass in TimeUnit.Hour or TimeUnit.Day.

OTHER TIPS

If you want strong typing, I'd recommend using an enum type rather than a string:

http://msdn.microsoft.com/en-us/library/cc138362.aspx

Using a abstract class is the normal way of doing it, you can't put input requirements on a interface itself.

The only other kinda-sorta option is write unit tests that pass in invalid dates and check to make sure that ArgumentException is thrown when you expect it to be thrown.

EDIT: After seeing the other comments and answers I did not realize you basically are trying to recreate a Enum. Read the other answers about that, it is likely what you want to do in reality and will be much faster than doing a !Contains(.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top