I'm working on an app where I need to call one of two data methods based on the generic type of the calling class. For example, if T is of type Foo, I'll call data.GetFoo():
private static List<T> GetObjectList(DateTime mostRecentProcessedReadTime)
{
using (MesReportingDal data = new MesReportingDal())
{
return data.GetFoo(mostRecentProcessedReadTime); // Notice GetFoo()
}
}
And if T is of type Bar, I'll call data.GetBar():
private static List<T> GetObjectList(DateTime mostRecentProcessedReadTime)
{
using (MesReportingDal data = new MesReportingDal())
{
return data.GetBar(mostRecentProcessedReadTime); // Notice GetBar()
}
}
Before now, I only needed one DAL method because all types were retrieved the same way. I now need to call one of two methods, depending on the type of T.
I'm trying to avoid something like this:
private static List<T> GetObjectList(DateTime mostRecentProcessedReadTime)
{
using (MesReportingDal data = new MesReportingDal())
{
if (T is Foo) { return data.GetFoo(mostRecentProcessedReadTime); }
if (T is Bar) { return data.GetBar(mostRecentProcessedReadTime); }
}
}
This violates OCP. Is there an elegant way to handle this, so I can get rid of my if statement?
Edit - This is what the types look like
public partial class Foo1 : IDataEntity { }
public partial class Foo2 : IDataEntity { }
public partial class Bar1 : IDataEntity { }
public partial class Bar2 : IDataEntity { }
These Foos and Bars are the DBML items used with Linq-to-SQL.
I would change GetFoo
and GetBar
to just be Get
, and make MesReportingDal
a generic too.
So I think you would end up with something like this:
private static List<T> GetObjectList(DateTime mostRecentProcessedReadTime)
{
using (var data = new MesReportingDal<T>())
{
return data.Get(mostRecentProcessedReadTime);
}
}
Incidentally, having the using
statement also requires that the MesReportingDal
implements IDisposable
, otherwise you'll get the following compile error:
'MesReportingDal': type used in a using statement must be implicitly convertible to 'System.IDisposable'
UPDATE
So after thinking about this some more and reading your feedback, one option you have is to extract a repository interface and push the creation back to a factory method. This will allow you to maintain the single data.Get(...)
call, but with different implementations based on T
public interface IRepository<T> : IDisposable
{
IList<T> Get(DateTime mostRecentRead);
}
public class FooRepo : IRepository<Foo>
{
public IList<Foo> Get(DateTime mostRecentRead)
{
// Foo Implementation
}
}
public class BarRepo : IRepository<Bar>
{
public IList<Bar> Get(DateTime mostRecentRead)
{
// Bar Implemenation
}
}
Your factory could then look something like this
public class RepositoryFactory
{
public static IRepository<T> CreateRepository<T>()
{
IRepository<T> repo = null;
Type forType = typeof(T);
if (forType == typeof(Foo))
{
repo = new FooRepo() as IRepository<T>;
}
else if (forType == typeof(Bar))
{
repo = new BarRepo() as IRepository<T>;
}
return repo;
}
}
And this would allow you to keep your initial code block clean
private static IList<T> GetObjectList(DateTime mostRecentProcessedReadTime)
{
using (var data = RepositoryFactory.CreateRepository<T>())
{
return data.Get(mostRecentProcessedReadTime);
}
}
Hope that helps.