Domanda

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.

È stato utile?

Soluzione

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top