I found myself struggling with some patterns when trying to implement a DAL for my application.
Some context concerning my knowlege:
- C# is quite new for me and some issues might be due to some lacking knowledge (in this case I would say especially with generics)
- Using Dependency injection is also something new for me, although I think I understand it properly now.
- The factory pattern is also new for me. I get it and I've used it with some libraries, but this is the first time I really implement it.
What I want to achieve :
I'm coding a DAL and to use it I need to retrieve a DatabaseReader object that depends on the object I want to link with my database. I want to be able to construct those objects dynamically while taking advantages of Dependency injection. A good way to do this according to my research is to create a factory that would be injected into my classes which would be able then to Instantiate them.
I got some good tips from this article: (How not to do dependency injection ) which has an example with a factory registration. But I haven't been successful properly understanding it and implementing it using the SimpleContainer of caliburn micro.
My code so far:
I'm implementing the DAL as shown in this article (Data Access Layer using the Template Pattern and Generics ) I will take for example a Mapper that I want a factory for (in reality I don't want to retreive it directly but it is simpler for the concept).
The base generic class :
abstract class MapperBase<T>
{
protected abstract T Map(IDataRecord record);
public Collection<T> MapAll(IDataReader reader){
...
}
}
a concrete mapper:
class LincolnTelemetryMapper : MapperBase<LincolnTelemetryModel>
{
protected override LincolnTelemetryModel Map(IDataRecord record)
{
try
{
LincolnTelemetryModel telemetry = new LincolnTelemetryModel();
telemetry.Timestamp = (DBNull.Value == record["measureDate"]) ?
null : (DateTime)record["measureDate"];
telemetry.Voltage = (DBNull.Value == record["voltage"]) ?
null : decimal.ToDouble((decimal)record["voltage"]);
...
} catch { ... }
}
}
And then the factory code (not in a working state) that I'm trying to implement and register in my IoC container:
interface IMapperFactory<T>
{
bool AppliesTo(Type type);
MapperBase<T> CreateMapper(object mappedObject);
}
class MapperFactory<T> : IMapperFactory<T>
{
public bool AppliesTo(Type type)
{
return typeof(T).Equals(type);
}
public MapperBase<T> CreateMapper(object mappedObject)
{
switch (mappedObject)
{
case LincolnTelemetryModel:
LincolnTelemetryMapper lincmapper = new LincolnTelemetryMapper();
MapperBase<LincolnTelemetryModel> telemetrymapper = lincmapper;
return (MapperBase<T>)telemetrymapper;
default:
return null;
}
}
}
My questions:
In the factory above, The mapper cannot be returned: The type MapperBase cannot be casted in MapperBase. There is probably something I'm not understanding well with the c# generics. can someone point me to the real issue here ?
Any way to do a generic factory that can work with any object without having to explicitly create each mapper. Unlike the example below, by registering something like MapperBase instead of the concrete implementation.
Some test code from the bootstrapper that I'm not satisfied with... and smell like misunderstanding something.
MapperFactory<LincolnTelemetryModel> lincolnTelemetryMapperFact = new MapperFactory<LincolnTelemetryModel>();
//register factory ?
container.Instance<MapperFactory<LincolnTelemetryModel>>(lincolnTelemetryMapperFact);
//or a mapped object ?
LincolnTelemetryModel testmodel = new LincolnTelemetryModel(); //in userClass
LincolnTelemetryMapper factoredMapper = lincolnTelemetryMapperFact.CreateMapper(testmodel);
container.RegisterPerRequest(LincolnTelemetryMapper, "key", factoredMapper);
edit:
I want to precise that I know the code above is useless but it serves as a step to implement something generic. I could of course directly register the mappers by type and be done with it. the goal is to generalize to only one factory for all Mappers. With the model object as an argument.
Thank you for your help,