Resolving multiple implementations with generics .net core - c#

I'm trying to figure out how to use multiple implementation of a base class with generics via dependency injection in .net core.
My base class is using generics so I can have different types of List in my response Dto.
I have successfully used many interface and base class implementations when there are no generics involved.
What I've tried so far.
Base class
public abstract class GeneratorBase<T>
{
public abstract ProcessorResponse<T> Process();
}
Response dto
public class ProcessorResponse<T>
{
public ProcessorResponse()
{
Data = new List<T>();
}
public List<T> Data { get; set; }
}
Implementation number 1
public class ConfigurationGenerator : GeneratorBase<ConfigurationModel>
{
public override ProcessorResponse<ConfigurationModel> Process()
{
return new ProcessorResponse<ConfigurationModel>();
}
}
Implementation number 2.
public class ApplicationGenerator : GeneratorBase<ApplicationModel>
{
public override ProcessorResponse<ApplicationModel> Process()
{
return new ProcessorResponse<ApplicationModel>();
}
}
Models
public class ConfigurationModel
{
public int Count { get; set; }
}
public class ApplicationModel
{
public string Title { get; set; }
}
My dependency injection to add the implementations.
public static void AddGenerators(this IServiceCollection services)
{
// add our generators
services.AddScoped<GeneratorBase<ConfigurationModel>, ConfigurationGenerator>();
services.AddScoped<GeneratorBase<ApplicationModel>, ApplicationGenerator>();
}
Main App this is where my error is happening.
public class GeneratorApp
{
// error because T is not implemented
private readonly IEnumerable<GeneratorBase> _generators;
// error because T is not implemented
public GeneratorApp(IEnumerable<GeneratorBase> generators)
{
_generators = generators ?? throw new ArgumentException(nameof(generators));
}
public void RunGenerator(string name)
{
// get the generator by name and run process
var generator = _generators.FirstOrDefault(c => c.GetType().Name == name);
var results = generator.Process();
}
}
Update IFoo Example
IFoo example that works.
public interface IFoo
{
string Name { get; }
}
public class Foo1 : IFoo
{
public string Name => "I'm Foo 1";
}
public class Foo2 : IFoo
{
public string Name => "I'm Foo 2";
}
Dependency injection to add the implementations.
public static void AddGenerators(this IServiceCollection services)
{
// add our Foo's
services.AddTransient<IFoo, Foo1>();
services.AddTransient<IFoo, Foo2>();
}
Main App
public class GeneratorApp
{
private IEnumerable<IFoo> _foos;
public GeneratorApp(IEnumerable<IFoo> foos)
{
_foos = foos;
RunGenerator("Foo1");
}
public void RunGenerator(string name)
{
foreach (var foo in _foos)
{
Console.WriteLine(foo.Name);
}
var foundFoo = _foos.FirstOrDefault(c => c.GetType().Name == name);
if (foundFoo != null)
{
Console.WriteLine(foundFoo.Name);
}
}
}
Console output
I'm Foo 1
I'm Foo 2
I'm Foo 1

The basics
You're misunderstanding the purpose (and correct usage) of dependency injection.
services.AddScoped<IFoo, Foo>();
To put it into words:
If you're creating a object whose constructor needs an IFoo, please insert a Foo instance.
That is the intention of dependency injection: to provide concrete objects even though they (the class' constructors) are asking for vague types.
It allows the classes to be vague, and thus not strongly depend on any particular implementation (= concrete classes).
Your problem
Very simply put, your constructor is asking a parameter type (IEnumerable<GeneratorBase>) that you never registered.
You only registered GeneratorBase<ConfigurationModel> and GeneratorBase<ApplicationModel>, which means that your dependency injection is only able to resolve constructor parameters of those two types. Anything else, the DI framework will throw an exception as it doesn't know how to fill it in.
The solution
It seems like you want a list of all (chosen) types to be injected. Therefore, you must register this exact type. For example:
services.AddScoped<IEnumerable<GeneratorBase>>(() => new List<GeneratorBase>()
{
new ConfigurationGenerator(),
new ApplicationGenerator()
});
This is just the shortest path to workable code. However, there are still further considerations, but your intention and use case simply isn't clear. I strongly suggest reading up on dependency injection as you are missing key knowledge on how to effectively leverage it.
Footnote: You did not post a definition for GeneratorBase (non-generic) but you did reference this type. I'm going to assume that this type exists and you forgot to add it to the question. If not, then there are also some misgivings about polymorphism with generics, which I also suggest you brush up on.

Related

Inheritance and extension of models in c# with multiple implementations of property within base

I have a pub/sub queue that returns what I'll call QueueMessages.
A QueueMessage has a Type and a Body. The type is always a string but the body varies depending on the type. I want the inheriting class to set the message type. I want to add my own local properties for storing on processing datatables.
I was hoping to be able to define a generic object for the body and override in the inheriting classes but it fails as I'm changing the return type.
Interface:
interface IBaseQueueMessage
{
Guid Id { get; set; }
string MessageType { get; }
object Message { get; set; }
DateTime ConsumeDate { get; set; }
}
Base class:
public abstract class BaseQueueMessage:IBaseQueueMessage
{
public Guid Id { get; set; }
public abstract string MessageType { get; }
public abstract object Message { get; set; }
public DateTime ConsumeDate => DateTime.Now;
}
Inheriting Classes (there are 7 or 8 different ones in total)
public sealed class Type1Message: BaseCallType
{
public override string MessageType => "Type1Message";
public override Type1Message Message { get; set; }
}
public class Type1Message
{
public string aaa { get; set; }
public int bbb { get; set; }
}
public sealed class Type2Message: BaseCallType
{
public override string MessageType => "Type2Message";
public override Type2Message Message { get; set; }
}
public class Type2Message
{
public string aaa { get; set; }
public string bbb { get; set; }
public int ccc {get; set;}
public bool ddd {get; set;}
}
The above fails as I'm trying to return a specific class instead of the generic object. I understand why it would fail, but I'd like to know what would be the correct way of doing this please? I could just define individual classes for each and to hell with the interface and inheritance but it feels wrong to approach it that way. I intend to map the QueueMessage directly onto the inheriting classes for each different type so I want the model to match exactly what I pick up from the queue.
Apologies in advance for probably missing something really obvious, it's been a while since I did any coding and this is a relatively new area to me.
Edited to add more details on implementation problem
Lots of this works, thanks. Where I still have a problem is in the MessageHandlerWrapper. If I debug, then the handler object from the constructor that the method tries to use in _handler = handler is always null.
In my .net core startup.cs I have:
void RegisterHandler<TMessageType, THandler>()
where TMessageType : class
where THandler : IMessageHandler<TMessageType>
{
serviceCollection.AddSingleton<TMessageType>();
serviceCollection.AddSingleton(
serviceProvider => new MessageHandlerWrapper<TMessageType>(serviceProvider.GetService<THandler>(), serviceProvider)
);
}
...and it's the ...=> new MessageHandlerWrapper<... near the end of that block that is resolved by the dependency when I'm debugging in the code mentioned above, so I can't see why the service isn't available at that point.
Is there some way I can manually try to debug this by resolving the service to a concrete handler in MessageHandlerWrapper to see where the problem may lie?
For completeness, the whole section in startup.cs is:
//set up message handlers
var msgFactory = new MessageHandlerFactory();
//create local function to make it easier to add service references
void RegisterHandler<TMessageType, THandler>()
where TMessageType : class
where THandler : IMessageHandler<TMessageType>
{
serviceCollection.AddSingleton<TMessageType>();
serviceCollection.AddSingleton(
serviceProvider => new MessageHandlerWrapper<TMessageType>(serviceProvider.GetService<THandler>(), serviceProvider)
);
}
// Type1MessageHandler, etc is the implementation of IMessageHandler<Type1>
RegisterHandler<Type1, Type1MessageHandler>();
RegisterHandler<Type2, Type2MessageHandler>();
RegisterHandler<Type3, Type3MessageHandler>();
RegisterHandler<Type4, Type4MessageHandler>();
// some string constants for message types would be better.
serviceCollection.AddSingleton<IMessageHandlerFactory>(serviceProvider =>
{
msgFactory.RegisterHandler("Type1",
serviceProvider.GetService<MessageHandlerWrapper<Type1>>);
msgFactory.RegisterHandler("Type2",
serviceProvider.GetService<MessageHandlerWrapper<Type2>>);
msgFactory.RegisterHandler("Type3",
serviceProvider.GetService<MessageHandlerWrapper<Type3>>);
msgFactory.RegisterHandler("Type4",
serviceProvider.GetService<MessageHandlerWrapper<Type4>>);
return msgFactory;
});
serviceCollection.AddSingleton<IMessageHandler, MessageRouter>();
Here's an approach. The intent of the design is to enable you to write type-safe generic message handler classes, but be able to call them when you're starting from a message of type object. Bridging from one to the other can be a pain, and I think it's at the heart of your question.
This doesn't use inheritance for the messages. (You mentioned you were open to not inheriting.) I don't think it would add any value in this scenario, although this could be adapted to use inheritance.
First, here's a generic Message<T> class. This doesn't replace your existing message class. It's just that in order to have a type-safe generic handler, you need a generic message.
public class Message<T>
{
public Message(T content, Guid id, string messageType, DateTime consumeDate)
{
Content = content;
Id = id;
MessageType = messageType;
ConsumeDate = consumeDate;
}
public T Content { get; }
public Guid Id { get; }
public string MessageType { get; }
public DateTime ConsumeDate { get; }
}
Next, here's an interface for a message handler. The implementation doesn't matter for this example. What matters is that whatever T is, you can write a class to handle it.
public interface IMessageHandler<T>
{
void HandleMessage(Message<T> message);
}
This next interface and class are intended to serve as a "bridge" from your non-generic message (which uses object) to your generic message handler:
public interface IMessageHandler
{
void HandleMessage(IQueueMessage message);
}
public class MessageHandlerWrapper<TMessage> : IMessageHandler
{
private readonly IMessageHandler<TMessage> _handler;
public MessageHandlerWrapper(IMessageHandler<TMessage> handler)
{
_handler = handler;
}
// This is the critical part - it gets us from object to TMessage.
public void HandleMessage(IQueueMessage message)
{
_handler.HandleMessage(
new Message<TMessage>(
(TMessage)message.Message,
message.Id,
message.MessageType,
message.ConsumeDate));
}
}
Then you'll need a factory that returns the correct IMessageHandler depending on the message type string:
public interface IMessageHandlerFactory
{
IMessageHandler GetHandler(string messageType);
}
Putting all of this together connects your non-generic message to your generic message handler:
public class MessageRouter : IMessageHandler
{
private readonly IMessageHandlerFactory _messageHandlerFactory;
public MessageRouter(IMessageHandlerFactory messageHandlerFactory)
{
_messageHandlerFactory = messageHandlerFactory;
}
public void HandleMessage(IQueueMessage message)
{
var handler = _messageHandlerFactory.GetHandler(message.MessageType);
handler.HandleMessage(message);
}
}
This class also implements IMessageHandler. It's going to take the message, without caring what the type is, use the factory to get a more specific handler, and route the message to that handler.
Now we need to implement the factory. Here's an implementation which will allow us to resolve handlers from an IServiceProvider without resorting to a service locator:
public class MessageHandlerFactory : IMessageHandlerFactory
{
private readonly Dictionary<string, Func<IMessageHandler>> _messageHandlers
= new Dictionary<string, Func<IMessageHandler>>(StringComparer.OrdinalIgnoreCase);
public void RegisterHandler(string messageType, Func<IMessageHandler> getHandlerFunction)
{
_messageHandlers[messageType] = getHandlerFunction;
}
public IMessageHandler GetHandler(string messageType)
{
if (_messageHandlers.ContainsKey(messageType))
return _messageHandlers[messageType]();
throw new InvalidOperationException($"No handler is registered for message type {messageType}.");
// Or you could return some default handler that does something else with
// unknown message types.
}
}
Now we can register implementations as follows:
public static class MessageHandlerServiceCollectionExtensions
{
public static IServiceCollection AddMessageHandlers(this IServiceCollection services)
{
void RegisterHandler<TMessageType, THandler>()
where TMessageType : class
where THandler : IMessageHandler<TMessageType>
{
services.AddSingleton<TMessageType>();
services.AddSingleton(
serviceProvider => new MessageHandlerWrapper<TMessageType>(serviceProvider.GetService<THandler>())
);
}
// MessageTypeOneHandler is the implementation of IMessageHandler<MessageTypeOne>
RegisterHandler<MessageTypeOne, MessageTypeOneHandler>();
RegisterHandler<MessageTypeTwo, MessageTypeTwoHandler>();
// some string constants for message types would be better.
services.AddSingleton<IMessageHandlerFactory>(serviceProvider =>
{
var factory = new MessageHandlerFactory();
factory.RegisterHandler("messagetypeone",
serviceProvider.GetService<MessageHandlerWrapper<MessageTypeOne>>);
factory.RegisterHandler("messagetypetwo",
serviceProvider.GetService<MessageHandlerWrapper<MessageTypeTwo>>);
return factory;
});
services.AddSingleton<IMessageHandler, MessageRouter>();
return services;
}
}
Having done all of this, does it seem a bit complex? It does to me, but I still consider it worth the effort. Why?
The message handlers are type safe instead of allowing object to propagate through the code. We're containing it like a disease. We can create simple, testable, single-responsibility classes that implement IMessageHandler<TMessage>.
Everything gets resolved from the container. That means the message handlers could all have their own unique dependencies, and that would be okay.
No reflection. It's not that reflection is evil, but once we go down that road it seems to get worse.
There is a clear path forward for the you or the next developer if you need to add handlers for more types. Even if they have no idea how to register the handlers and they don't do it, the exceptions will give them a clear path forward, showing them what they need to do. If it's registered it will get resolved. If it's not, the factory will throw an exception.
Finally, all of this is testable, even the factory. If the message types were an enum you could just run one test to ensure that there's a handler for every type.
[DataTestMethod]
[DataRow("MessageTypeOne")]
[DataRow("MessageTypeTwo")]
public void FactoryResolvesMessageHandlers(string messageType)
{
var services = new ServiceCollection();
services.AddMessageHandlers();
var provider = services.BuildServiceProvider();
var factory = provider.GetService<IMessageHandlerFactory>();
var handler = factory.GetHandler(messageType);
Assert.IsNotNull(handler);
}

Parametrized Abstract Factory / Factory Method / other creation patterns

I want to have some factory (doesn't matter if Abstract Factory pattern or Factory Method - looks like the second is specific form of the first one. In my case only one object should be created). The thing is that although created products are similar, they depends on some arguments.
How to prepare this architecture in compliance with design patterns?
Current approach below
public abstract class Product {}
public class MyProduct : Product
{
public bool Abc { get; set; }
}
public class YourProduct : Product {}
public abstract class ProductFactory
{
//in some cases parameter not in use
public abstract Product Create(HelpData additionalData);
}
public class MyProductFactory : ProductFactory
{
public override Product Create(HelpData additionalData)
{
return new MyProduct {Abc = additionalData.SomethingImportantForMyProduct};
}
}
public class YourProductFactory : ProductFactory
{
//unused parameter
public override Product Create(HelpData additionalData)
{
return new YourProduct();
}
}
public class HelpData
{
public bool SomethingImportantForMyProduct { get; set; }
}
EDIT
I see it's not clear so will repeat.
Usually I'm not using patterns just because of using them. But this problem seems not to be border case. Looks rather quite frequent. Going further I believe there's design pattern suitable to this, but I'm not sure which one. For now looks like abstract factory is not right choice.
Don't use design-patterns because you're using design-patterns. Always have in mind when to use one and when not. In your circumstances at least the abstract factory-pattern is wrong, as it assumes all factories to work with the same parameters. So if you have different parameters you surely need different factories.
However there's no way for the abstract factory to guess how to get an instance of a HelpData in some case but not in the other, so either pass it to every abstract factory or completely omit this further abstraction and stay with two independent factories:
public abstract class Product {}
public class MyProduct : Product
{
public bool Abc { get; set; }
}
public class YourProduct : Product {}
public class MyProductFactory
{
public Product Create(HelpData additionalData)
{
return new MyProduct {Abc = additionalData.SomethingImportantForMyProduct};
}
}
public class YourProductFactory
{
//unused parameter
public Product Create()
{
return new YourProduct();
}
}
public class HelpData
{
public bool SomethingImportantForMyProduct { get; set; }
}
Exposing a parameter only used within one factory to all factories isn't a good idea.
Besides this just imagine you don't have factories but any other classes that have a Create-method, where one needs a parameter, but the other one does not. Why should those two classes derive from the same base-class (in your case the abstract factory), when the don't have any common members? There's apparently no reason for this, so don't overcomplicate things just for the sake of using a pattern which doesn't fit.
Depending on where and how you retrieve additional data you could inject that data to the factory which will use it to construct the object:
public abstract class ProductFactory
{
public abstract Product Create();
}
public class MyProductFactory : ProductFactory
{
private HelpData additionalData;
public MyProductFactory(HelpData additionalData)
{
this.additionalData = additionalData;
}
public override Product Create()
{
return new MyProduct {Abc = additionalData.SomethingImportantForMyProduct};
}
}
public class YourProductFactory : ProductFactory
{
public override Product Create()
{
return new YourProduct();
}
}
Instead of passing HelpData to constructor of a factory you could inject a service that knows how to retrieve HelpData specific to the object being created. You could pass some other parameter to Create method if it is used for both factories.
I have also googled a bit and found good answer that explains why not https://stackoverflow.com/a/6241219/2138959. Passing a dictionary or a type that has property of dictionary type is also and option but in such approaches client has too much knowledge of a type it want to be created to use abstract factory.

Factory method with DI and IoC

I am familiar with these patterns but still don't know how to handle following situation:
public class CarFactory
{
public CarFactory(Dep1,Dep2,Dep3,Dep4,Dep5,Dep6)
{
}
public ICar CreateCar(type)
{
switch(type)
{
case A:
return new Car1(Dep1,Dep2,Dep3);
break;
case B:
return new Car2(Dep4,Dep5,Dep6);
break;
}
}
}
In general the problem is with amount of references that needs to be injected. It will be even worse when there are more cars.
First approach that comes to my mind is to inject Car1 and Car2 in factory constructor but it is against factory approach because factory will return always the same object. The second approach is to inject servicelocator but it's antipattern everywhere. How to solve it?
Edit:
Alternative way 1:
public class CarFactory
{
public CarFactory(IContainer container)
{
_container = container;
}
public ICar CreateCar(type)
{
switch(type)
{
case A:
return _container.Resolve<ICar1>();
break;
case B:
return _container.Resolve<ICar2>();
break;
}
}
}
Alternative way 2 (too hard to use because of too many of dependencies in tree):
public class CarFactory
{
public CarFactory()
{
}
public ICar CreateCar(type)
{
switch(type)
{
case A:
return new Car1(new Dep1(),new Dep2(new Dep683(),new Dep684()),....)
break;
case B:
return new Car2(new Dep4(),new Dep5(new Dep777(),new Dep684()),....)
break;
}
}
}
Having a switch case statement inside of a factory is a code smell. Interestingly, you don't seem to be focusing on solving that issue at all.
The best, most DI friendly solution for this scenario is the strategy pattern. It allows your DI container to inject the dependencies into the factory instances where they belong, without cluttering up other classes with those dependencies or resorting to a service locator.
Interfaces
public interface ICarFactory
{
ICar CreateCar();
bool AppliesTo(Type type);
}
public interface ICarStrategy
{
ICar CreateCar(Type type);
}
Factories
public class Car1Factory : ICarFactory
{
private readonly IDep1 dep1;
private readonly IDep2 dep2;
private readonly IDep3 dep3;
public Car1Factory(IDep1 dep1, IDep2 dep2, IDep3 dep3)
{
this.dep1 = dep1 ?? throw new ArgumentNullException(nameof(dep1));
this.dep2 = dep2 ?? throw new ArgumentNullException(nameof(dep2));
this.dep3 = dep3 ?? throw new ArgumentNullException(nameof(dep3));
}
public ICar CreateCar()
{
return new Car1(this.dep1, this.dep2, this.dep3);
}
public bool AppliesTo(Type type)
{
return typeof(Car1).Equals(type);
}
}
public class Car2Factory : ICarFactory
{
private readonly IDep4 dep4;
private readonly IDep5 dep5;
private readonly IDep6 dep6;
public Car2Factory(IDep4 dep4, IDep5 dep5, IDep6 dep6)
{
this.dep4 = dep4 ?? throw new ArgumentNullException(nameof(dep4));
this.dep5 = dep5 ?? throw new ArgumentNullException(nameof(dep5));
this.dep6 = dep6 ?? throw new ArgumentNullException(nameof(dep6));
}
public ICar CreateCar()
{
return new Car2(this.dep4, this.dep5, this.dep6);
}
public bool AppliesTo(Type type)
{
return typeof(Car2).Equals(type);
}
}
Strategy
public class CarStrategy : ICarStrategy
{
private readonly ICarFactory[] carFactories;
public CarStrategy(ICarFactory[] carFactories)
{
this.carFactories = carFactories ?? throw new ArgumentNullException(nameof(carFactories));
}
public ICar CreateCar(Type type)
{
var carFactory = this.carFactories
.FirstOrDefault(factory => factory.AppliesTo(type));
if (carFactory == null)
{
throw new InvalidOperationException($"{type} not registered");
}
return carFactory.CreateCar();
}
}
Usage
// I am showing this in code, but you would normally
// do this with your DI container in your composition
// root, and the instance would be created by injecting
// it somewhere.
var strategy = new CarStrategy(new ICarFactory[] {
new Car1Factory(dep1, dep2, dep3),
new Car2Factory(dep4, dep5, dep6)
});
// And then once it is injected, you would simply do this.
// Note that you could use a magic string or some other
// data type as the parameter if you prefer.
var car1 = strategy.CreateCar(typeof(Car1));
var car2 = strategy.CreateCar(typeof(Car2));
Note that because there is no switch case statement, you can add additional factories to the strategy without changing the design, and each of those factories can have their own dependencies that are injected by the DI container.
var strategy = new CarStrategy(new ICarFactory[] {
new Car1Factory(dep1, dep2, dep3),
new Car2Factory(dep4, dep5, dep6),
new Car3Factory(dep7, dep8, dep9)
});
var car1 = strategy.CreateCar(typeof(Car1));
var car2 = strategy.CreateCar(typeof(Car2));
var car3 = strategy.CreateCar(typeof(Car3));
Answering your comment about code example with Composition Root.
You can create following and this is not a Service Locator.
public class CarFactory
{
private readonly Func<Type, ICar> carFactory;
public CarFactory(Func<Type, ICar> carFactory)
{
this.carFactory = carFactory;
}
public ICar CreateCar(Type carType)
{
return carFactory(carType);
}
and this is how look your Composition Root using Unity DI container :
Func<Type, ICar> carFactoryFunc = type => (ICar)container.Resolve(type);
container.RegisterInstance<CarFactory>(new CarFactory(carFactoryFunc));
I answered a similar question some time ago. Basically it's all about your choice. You have to choose between verbosity (which gives you more help from a compiler) and automation, which allows you to write less code but is more prone to bugs.
This is my answer supporting verbosity.
And this is also a good answer that supports automation.
EDIT
I believe the approach you consider wrong is actually the best. Truth being said, usually there won't so many dependencies in there. I like this approach because it's very explicit and rarely results in runtime errors.
Alternative way 1:
This one is bad. It's actually a service locator, which is considered an anti-pattern.
Alternative way 2
Like you wrote, it's not easy to use if mixed with IOC containter. However in some case a similar approach (poor man's DI) can be useful.
All in all, I wouldn't bother having "many" dependencies in your factories. It's a simple, declarative code. It takes seconds to write and can save you hours of struggling with runtime errors.
I would consider giving the dependencies a good structure so you can utilize something similar to Wiktor's answer, but I would abstract the Car factory itself. Then, you don't use the if..then structure.
public interface ICar
{
string Make { get; set; }
string ModelNumber { get; set; }
IBody Body { get; set; }
//IEngine Engine { get; set; }
//More aspects...etc.
}
public interface IBody
{
//IDoor DoorA { get; set; }
//IDoor DoorB { get; set; }
//etc
}
//Group the various specs
public interface IBodySpecs
{
//int NumberOfDoors { get; set; }
//int NumberOfWindows { get; set; }
//string Color { get; set; }
}
public interface ICarSpecs
{
IBodySpecs BodySpecs { get; set; }
//IEngineSpecs EngineSpecs { get; set; }
//etc.
}
public interface ICarFactory<TCar, TCarSpecs>
where TCar : ICar
where TCarSpecs : ICarSpecs
{
//Async cause everything non-trivial should be IMHO!
Task<TCar> CreateCar(TCarSpecs carSpecs);
//Instead of having dependencies ctor-injected or method-injected
//Now, you aren't dealing with complex overloads
IService1 Service1 { get; set; }
IBuilder1 Builder1 { get; set; }
}
public class BaseCar : ICar
{
public string Make { get; set; }
public string ModelNumber { get; set; }
public IBody Body { get; set; }
//public IEngine Engine { get; set; }
}
public class Van : BaseCar
{
public string VanStyle { get; set; }
//etc.
}
public interface IVanSpecs : ICarSpecs
{
string VanStyle { get; set; }
}
public class VanFactory : ICarFactory<Van, IVanSpecs>
{
//Since you are talking of such a huge number of dependencies,
//it may behoove you to properly categorize if they are car or
//car factory dependencies
//These are injected in the factory itself
public IBuilder1 Builder1 { get; set; }
public IService1 Service1 { get; set; }
public async Task<Van> CreateCar(IVanSpecs carSpecs)
{
var van = new Van()
{
//create the actual implementation here.
};
//await something or other
return van;
}
}
I didn't list it, but you can implement multiple types of cars and their corresponding factories now and use DI to inject whatever you need.
First, you have a concrete factory, an IoC container could be an alternative rather than something to help you there.
Then, just refactor the factory to not to expect a full possible parameter list in the factory constructor. This is the primary issue - why are you passing so many parameters if the factory method doesn't need them?
I would rather pass specific parameters to the factory method
public abstract class CarFactoryParams { }
public class Car1FactoryParams : CarFactoryParams
{
public Car1FactoryParams(Dep1, Dep2, Dep3)
{
this.Dep1 = Dep1;
...
}
public class Car2FactoryParams
...
public class CarFactory
{
public ICar CreateCar( CarFactoryParams params )
{
if ( params is Car1FactoryParams )
{
var cp = (Car1FactoryParams)params;
return new Car1( cp.Dep1, cp.Dep2, ... );
}
...
if ( params is ...
By encapsulating the parameter list in a specific class you just make the client provide exactly these parameters that are required for specific factory method invocation.
Edit:
Unfortunately, it was not clear from your post what are these Dep1, ... and how you use them.
I suggest following approach then that separates the factory provider from actual factory implementation. This approach is known as the Local Factory pattern:
public class CarFactory
{
private static Func<type, ICar> _provider;
public static void SetProvider( Func<type, ICar> provider )
{
_provider = provider;
}
public ICar CreateCar(type)
{
return _provider( type );
}
}
The factory itself doesn't have any implementation, it is here to set the foundation to your domain API, where you want your car instances to be created with this API only.
Then, in the Composition Root (somewhere near the starting point of the app where you configure your actual container), you configure the provider:
CarFactory.SetProvider(
type =>
{
switch ( type )
{
case A:
return _container.Resolve<ICar1>();
case B:
return _container.Resolve<ICar2>();
..
}
);
Note that this example implementation of the factory's provider uses a delegate but an interface could also be used as a specification for an actual provider.
This implementation is basically #1 from your edited question, however, it doesn't have any particular downsides. The client still calls:
var car = new CarFactory().CreareCar( type );
Many DI containers support the notion of named dependencies.
E.g. (Structuremap syntax)
For<ICar>().Use<CarA>().Named("aCar");
Container.GetNamedInstance("aCar") // gives you a CarA instance
If you use something like a convention, a rule how the name is derived from the concrete car type itself, you have a situation where you don't need to touch the factory anymore when you extend the system.
Using this in a factory is straightforward.
class Factory(IContainer c) {
public ICar GetCar(string name) {
Return c.GetNamedInstance(name);
}
}

Is There a Name for this Pattern

I've used this pattern many times in a variety of places, usually alongside a plugin pattern.
Some example ways I've used it are for messaging systems, such as creating subscribers to various types of unrelated messages. I've also used it for generic integration workflows that each need a differently shaped context object.
Basically the pattern consists of defining a blank marker interface for a message or context. Then defining a high level workflow interface that works with the message/context interface. You can then use a factory to get a concrete instance of the workflow, and if needed, the workflow can also be responsible for parsing its message / context from a common data format.
Next, you create an abstract generic base workflow whose responsibilty is just to map calls to the interface methods, which pass around the useless marker interface, into calls to abstract methods that take the concrete version of the message/context.
Hopefully that makes sense. I'll provide a code example below. I'd love to know if this pattern has a name because I've noticed that I've used it about 4-5 times now. Also, I'm just fleshing out how to explain the pattern, so if anything about my explanation doesn't make sense please let me know that as well.
The main point is that you can have multiple classes with different method signatures that can still be called via a common interface:
End Result
public class ConcreteA : Base<MessageA>
{
public void Process(MessageA message){...}
public MessageA Parse(IDictionary data){...}
}
public class ConcreteB : Base<MessageB>
{
public void Process(MessageB message){...}
public MessageB Parse(IDictionary data){...}
}
//And both can by called by...
public void Main(){
var data = GetDataFromIntegrationSource(someContext);
IWorkflow impl = Factory.GetConcrete(someContext);
//So in your classes you're able to work with strongly typed parameters,
//But in the consuming code you still can use a common interface
//Consuming code never even knows what the strong type is.
IMessage msg = impl.Parse(data);
impl.Process(msg);
}
FULL EXAMPLE
High Level Interfaces
public interface IGenericeMarkerInterface
{
}
public interface IGenericWorkflow
{
void Process(IGenericeMarkerInterface messageOrContext);
IGenericeMarkerInterface Parse(IDictionary<string, string> commonDataFormat);
}
Abstract Base for Mapping to Concrete Methods
public abstract class GenericWorkflowBase<T> : IGenericWorkflow where T : IGenericeMarkerInterface
{
public void Process(IGenericeMarkerInterface messageOrContext)
{
Process((T)messageOrContext);
}
public IGenericeMarkerInterface Parse(IDictionary<string, string> commonDataFormat)
{
return DoParse(commonDataFormat);
}
public abstract void Process(T messageOrContext);
public abstract T DoParse(IDictionary<string, string> commonDataFormat);
}
Mapping Attributes
public class MappingAttributeUsedByFactoryAttribute : Attribute
{
public WorkflowType SomePropertyForMapping { get; set; }
}
Concrete Implementations
public class SomeRandomlyShapedMessageOrContext : IGenericeMarkerInterface
{
public int ID { get; set; }
public string Data { get; set; }
}
[MappingAttributeUsedByFactory(WorkflowType.IntegrationPartnerB)]
public class ConcreteWorkflow : GenericWorkflowBase<SomeRandomlyShapedMessageOrContext>
{
public override void Process(SomeRandomlyShapedMessageOrContext messageOrContext)
{
//TODO: process the strongly typed message
}
public override SomeRandomlyShapedMessageOrContext DoParse(IDictionary<string, string> commonDataFormat)
{
//TODO: parse the common data into the strongly typed message
}
}
Factory
public static class WorkflowFactory
{
public static IGenericWorkflow Get(WorkflowType workflow)
{
//TODO: find the concrete workflow by inspecting attributes
}
}
Example Usage
public static class Program
{
public static void Main(string[] args)
{
//this could be driven by a UI or some contextual data
var someSortOfWorkflowIdentifier = (WorkflowType)args[0];
var data = GetSomeDictionaryOfData();
var workflow = WorkflowFactory.Get(someSortOfWorkflowIdentifier);
workflow.Process(workflow.Parse(data));
}
}
Yes, it's exactly same as you named it: Marker interface

Autofac - resolving component with parameters dynamically

I have a class that takes an interface as a constructor argument. There are two implementations of this interface and I want to decide what implementation to use at runtime based on a variable.
The problem is that the class above is deep in an object heirarchy that is resolved by Autofac and so I can't pass in the argument.
Somehing like below is what I am trying to achieve.
public interface IInterface1 {}
public interface IInterface2 {}
public class Class1 : IInterface2
{
public Class1(IInterface1 interface1)
{
}
}
public class Class2
{
public Class2(IInterface2 interface2)
{
}
}
public class Class3
{
public void GetClass2Instance(string interface1ImplementationToChoose)
{
// want to change which implementation of IInterface1 is resolved based on the interface1ImplementationToChoose variable
var class2 = container.Resolve<Class2>();
}
}
Any ideas?
UPDATE:
To clarify, this is an existing object hierarchy that is used by existing applications that work fine. Also, the object model is much larger than the one shown in this example. As a result I don't really want to have to pass down a factory to each constructor in the object graph to be used by a class deep in that graph.
Is there a way of getting a different implementation of IInterface1 passed into Class1 without Class2 knowing anything about it?
Thanks
Yes, inject a factory that hides how the types are chosen:
public class Class3
{
private Func<string, Class2> _class2Factory;
public Class3(Func<string, Class2> class2Factory)
{
_class2Factory = class2Factory;
}
public void GetClass2Instance(string interface1ImplementationToChoose)
{
var class2 = _class2Factory(interface1ImplementationToChoose);
}
}
And then the container setup, something along these lines:
builder.RegisterType<Implementation1>().Named("imp1").As<IInterface1>();
builder.RegisterType<Implementation2>().Named("imp2").As<IInterface1>();
builder.Register<Func<string, Class2>>(c =>
{
var context = c.Resolve<IComponentContext>();
return imp => new Class2(context.Resolve<IInterface1>(imp));
});
builder.RegisterType<Class3>();
You can now use Class3 like this:
public class Class4
{
public Class4(Class3 class3)
{
var class2with1 = class3.GetClass2Instance("imp1");
var class2with2 = class3.GetClass2Instance("imp2");
}
}
NOTE: I have assumed that you meant that Class2 should be injected with varying implementations of the same interface IInterface1. Your sample is a bit confusing since you are showing two classes that implements different interfaces.

Categories

Resources