LINQ to SQL Covariance - is this the right way to do this?
I have several database - Elephants, Giraffes, Gorillas, etc - each of which has an Inputs and Results table named ElephantInputs, ElephantResults, GiraffeInputs, GiraffeResults, GorillaInputs, GorillaResults, respectively. I can't control the table naming.
I'm using LINQ to SQL to automatically generate the ElephantInputs, ElephantResults, GiraffeInputs, GiraffeResults, etc classes.
I want to write a single class, Processor(), that can read input from any of these databases and process it. I have a Factory method that instantiates a Processor based on the user's choices.
The first thing I did is create an interface for Input and Result objects and a partial class for each database so that its input and result objects implement that interface. That gave me a common interface for each animal. I also created a repository class for each database that has some methods to return items from the database.
public interface IBaseInput
{
int ID { get; set; }
string InputA { get; set; }
int InputB { get; set; }
double InputC { get; set; }
}
public interface IBaseResult
{
int ID { get; set; }
string ResultA { get; set; }
int ResultB { get; set; }
double ResultC { get; set; }
}
public interface IRepository<I, R>
where I : IBaseInput
where R : IBaseResult
{
IQueryable<I> GetInputs();
IQueryable<R> GetResults();
}
public partial class GorillaInput : IBaseInput
{
}
public partial class GorillaResult : IBaseResult
{
}
// A concrete repository for Gorillas
public class GorillaRepository : IRepository<GorillaInput, GorillaResult>
{
GorillaDataContext db = new GorillaDataContext(GetConnectionString("Gorillas"));
public IQueryable<GorillaInput> GetInputs()
{
return from p in db.GorillaInputs select p;
}
public IQueryable<GorillaResult> GetResults()
{
return from r in db.GorillaResults select r;
}
}
Next, I created an interface for my Processor
public interface IProcessor
{
void Process();
}
Here's a concrete Processor, and the factory that creates it.
public class Processor<T, I, R> : IProcessor
where T : class, IRepository<I, R>, new()
where P : IBaseInput
where R : IBaseResult
{
public void Process()
{
// Do some stuff ...
T repository = new T(); // Get results from the rater tables
IEnumerable<I> inputs = repository.GetInputs();
IEnumerable<R> results = repository.GetResults();
// Do some stuff with inputs and outputs...
}
}
public static class ProcessorFactory
{
public static IProcessor GetProcessor(string animal)
{
switch (animal) {
case "Elephant":
return new Processor<ElephantRepository, ElephantInput, ElephantResult>();
case "Giraffe":
return new Processor<GiraffeRepository, GiraffeInput, GiraffeResult>();
case "Gorilla":
开发者_StackOverflow社区return new Processor<GorillaRepository, GorillaInput, GorillaResult>();
default:
return null;
}
}
}
Finally, here's the program that calls the processor:
class Program
{
public static void Main()
{
IProcessor processor = ProcessorFactory.GetProcessor("Gorilla");
processor.Process();
}
}
Am I doing this right? Is there a less complicated way? Thanks
With all of your concrete types implementing interfaces, why bother with generics at all?
public class Processor
{
public void Process(IRepository repository)
{
// Do some stuff ...
IEnumerable<IBaseInput> inputs = repository.GetInputs();
IEnumerable<IBaseResult> results = repository.GetResults();
// Do some stuff with inputs and outputs...
}
}
精彩评论