Using Autofac to switch a concrete implemetation of an abstract factory - c#

I am humbling with a problem related to AutoFac and the the abstract factory pattern. My Example is a a service to use an IRepositoryFactory to create a Repository based on JSON or InMemory related to the user input.
// Abstract Factory
public interface IRepositoryFactory{
IRepository Create(string databaseIdentifier);
}
// JSON
public class JsonRepositoryFactory{
public IRepository Create(string databaseIdentifier){
return new JsonRepository(databaseIdentifier);
}
}
// InMemory
public class MemoryRepository{
public IRepository Create(string databaseIdentifier){
return new MemoryRepository(databaseIdentifier);
}
}
The Service should pull the Factory by Constructor Injection.
public interface IShopService{
public string Name {get;}
}
public class BeerShop : IShopService {
public string Name {get; private set;}
private readonly IRepository _repository;
public BeerShop(IRepositoryFactory repositoryFactory){
Name = "beershop";
_repository = repositoryFactory.Create(Name);
}
}
So far I am good with this. But the initialization is not my favorite.
var builder = new ContainerBuilder();
var userInput = ReadInput();
if(userInput = "json")
builder.RegisterType<IRepositoryFactory>().As<JsonRepositoryFactory>();
else
builder.RegisterType<IRepositoryFactory>().As<MemoryRepositoryFactory>();
builder.RegisterType<IShopService>.As<BeerShop>();
var container = builder.build();
[...]
var service = container.Resolve<IShoptService>();
// and so on ...
Is this the right approach to solve it? I am not convinced by my own design because it forces the user input before the initialization of the container. What if the user has to change the Repository while runtime? Is the abstract factory pattern the right tool to solve this problem?

Since the type of repository is known at the time the container is configured, you should register the specific repository directly. There is no need to introduce a factory, as there hardly ever is a reason to introduce a factory abstraction.
Example:
var builder = new ContainerBuilder();
var userInput = ReadInput();
if(userInput = "json")
builder.Register<IRepository>(c => new JsonRepository("dbidentifier"));
else
builder.Register<IRepository>(c => new MemoryRepository());
builder.RegisterType<BeerShop>.As<IShopService>();
var container = builder.build();
[...]
var service = container.Resolve<IShopService>();
This code allows the BeerShop to be simplified, because its constructor would be simple and it now it only depends on IRepository instead of IRepositoryFactory and IRepository. This simplifies testing and makes it easier to reason about this class. Furthermore, it removes the unneeded abstraction.

If you want to change the behaviour of the factory during runtime, then you have to move the logic of deciding the type of IRepository being created to the factory itself. You can adapt the pattern and tweak it to fit your requirements rather than conforming to the specific way of doing it.
The following is a way to do it, if you think about it, you can find different ways of adapting it.
public interface IRepository
{
//repository contracts
}
public interface IRepositoryFactory
{
IRepository Create(string arguments);
}
public interface IRepositoryBuilder
{
RepositoryType Type { get; }
IRepository Create(string args);
}
public class ApplicationSettings
{
public RepositoryType RepositoryType { get; set; }
}
public enum RepositoryType { Json, Text }
// Default implementation of repository factory based on applicationsettings.
public class ConfigurableRepositoryBuilder:IRepositoryFactory
{
private readonly ApplicationSettings _settings;
private readonly IEnumerable<IRepositoryBuilder> _repositoryBuilders;
public ConfigurableRepositoryBuilder(ApplicationSettings settings, IEnumerable<IRepositoryBuilder> repositoryBuilders)
{
_settings = settings;
_repositoryBuilders = repositoryBuilders;
}
public IRepository Create(string arguments)
{
var builder = _repositoryBuilders.First(x => x.Type == _settings.RepositoryType);
//configure builder settings and then call create
return builder.Create(arguments);
}
}
Now you can change the global settings anytime and you will get new type of repository from the next call onwards. Instead of a global singleton, you can read from app.config or other settings file also.
You now want to implement the IRepositoryBuilder for each type of supported IRepository Type

Related

Dependency Injection: how do I integrate values received from method parameters into dependencies that I want to resolve as constructor parameters?

Please bear with me - this is a complicated question, and I've simplified it as much as I am able. (I'm using ASP.NET web API and AutoFac and omitted a bunch of configuration for brevity.)
My goal is to maximize the extent to which dependency-injection is handled by a DI framework, in a situation where not all dependencies of some objects can be known until runtime.
Our players are:
a CONTROLLER class that accepts web requests, the entry point to the app - the input includes repoName
a REPOSITORY RESOLVER class, a factory that resolves a repoName into a specific REPOSITORY. Here's its implementation:
public class RepositoryResolver : IRepositoryResolver
{
public IRepository Resolve(string repoName)
{
return new Repository(new Input { RepoName = repoName });
}
}
a REPOSITORY class (representing a DB or whatever). Here's its implementation:
public class Repository : IRepository
{
private readonly Input input; // proxy for connection string or other identifying information
public Repository (Input input)
{
this.input = input;
}
public string[] Get()
{
return new[] { "I", "am", "a", input.RepoName };
}
}
a BUSINESS LOGIC class that computes a result. The BUSINESS LOGIC class depends on a single repository; it knows nothing of multiple repositories or the repository resolver because it's not concerned with them. Here's its implementation:
public class BusinessLogic : IBusinessLogic
{
private readonly IRepository repository;
public BusinessLogic(IRepository repository)
{
this.repository = repository;
}
public string[] Compute()
{
return repository.Get();
}
}
Procedurally, what I'm trying to accomplish (in this stripped-down toy example) is very straightforward. Here's an example implementation of the controller:
Proposed Answer #1 - Pure DI (no container)
public class PureDIController : ApiController
{
public ProceduralValuesController() { }
public IEnumerable<string> Get(string repoName)
{
IRepositoryResolver repoSource = new RepositoryResolver();
IRepository repo = repoSource.Resolve(repoName);
IBusinessLogic businessLogic = new BusinessLogic(repo);
return businessLogic.Compute();
}
}
...and this works, but obviously I'm not using a DI container here. When using pure DI like this, changes to one player tend to have ripple effects beyond its immediate collaborators and potentially through many layers (not represented here); I feel like moving this composition logic into a DI container will reduce a lot of that type of refactoring. That's the value proposition of this question.
However, when I try to rewrite this class using dependency-injection, I encounter a problem: the BUSINESS LOGIC depends on the REPOSITORY, so it cannot be resolved by a pre-created DI container. Hence, I cannot resolve the hand-waving comment here:
public class DIValuesController : ApiController
{
private readonly IRepositoryResolver repoSource;
private readonly IBusinessLogic businessLogic;
public DIValuesController(
IRepositoryResolver repoSource,
IBusinessLogic businessLogic)
{
this.repoSource = repoSource;
this.businessLogic = businessLogic;
}
public IEnumerable<string> Get(string repoName)
{
var repo = repoSource.Resolve(repoName);
/* ...handwaving to integrate repo into businessLogic... */
return businessLogic.Compute();
}
}
...because IBusinessLogic cannot be resolved at the time the controller is instantiated.
I've developed several possible solutions, and I will add them as potential answers. However, I don't like any of them, hence the post. ¯_(ツ)_/¯ Please surprise me with something I haven't thought of yet!
Yet another possibility - pass IBusinessLogic to Controller not as an instance, but as a factory (i.e. Func<string, IBusinessLogic>) and in Methode Compute Fall factory with repoName.
See, for example:
https://autofaccn.readthedocs.io/en/latest/advanced/delegate-factories.html
Answer #2 - Pass parameters as necessary
This solution abandons the original premise that we can fruitfully convert a method parameter into a constructor parameter. Instead, it assumes that the repoName (or some equivalent differentiator) will need to be passed into any function that requires that information. Here's one possible example implementation of the controller (note that BusinessLogic now requires an additional parameter):
public class ParameterPassingController : ApiController
{
private readonly IBusinessLogic businessLogic;
public ParameterPassingController(
IBusinessLogic businessLogic)
{
this.businessLogic = businessLogic;
}
public IEnumerable<string> Get(string repoName)
{
return businessLogic.Compute(repoName);
}
}
And here's the new implementation of BusinessLogic:
public class BusinessLogic : IBusinessLogic
{
private readonly IRepositoryResolver repositoryResolver;
public BusinessLogic(IRepository repositoryResolver)
{
this.repositoryResolver = repositoryResolver;
}
public string[] Compute(string repoName)
{
var repo = repositoryResolver.Resolve(repoName);
return repo.Get();
}
}
This solution feels very awkward because it modifies the BusinessLogic class to depend on a less direct object than it did before. A class's dependencies should be determined by the class, not by the needs of the caller. The BusinessLogic class was better the way it was before, and any solution that causes us to make it more complicated is probably not a good one.
Answer #3 - Introduce additional resolvers
This solution adds a BUSINESS LOGIC RESOLVER, using the same pattern as the REPOSITORY RESOLVER. (Factory pattern?)
public class BusinessLogicResolverController : ApiController
{
private readonly IRepositoryResolver repoSource;
private readonly IBusinessLogicResolver businessLogicSource;
public BusinessLogicResolverController(
IRepositoryResolver repoSource,
IBusinessLogicResolver businessLogicSource)
{
this.repoSource = repoSource;
this.businessLogicSource = businessLogicSource;
}
public IEnumerable<string> Get(string repoName)
{
var repo = repoSource.Resolve(repoName);
var businessLogic = businessLogicSource.Resolve(repo);
return businessLogic.Compute();
}
}
The thing I don't like about this is that if there are many classes that depend on a single IRepository (and in my non-trivial example, there are many), I need to create a Resolver for each of them. That also complicates other things that DI containers can help with like decorator application and stuff.
Answer #4 - Introduce temporal coupling
This solution replaces the registered implementation of IRepository with a class that also implements IRepositoryManager, allowing it to be pointed at the appropriate repo at runtime. Here's what the controller looks like now:
public class TemporallyCoupledController : ApiController
{
private readonly IRepositoryManager repoManager;
private readonly IBusinessLogic businessLogic;
public TemporallyCoupledController(
IRepositoryManager repoManager,
IBusinessLogic businessLogic)
{
this.repoManager = repoManager;
this.businessLogic = businessLogic;
}
public IEnumerable<string> Get(string repoName)
{
repoManager.Set(repoName);
return businessLogic.Compute();
}
}
...and here's the implementation of IRepositoryManager:
public class RepositoryManager : IRepositoryManager, IRepository
{
private readonly IRepositoryResolver resolver;
private IRepository repo = null;
public RepositoryManager(IRepositoryResolver resolver)
{
this.resolver = resolver;
}
void IRepositoryManager.Set(string repoName)
{
this.repo = resolver.Resolve(repoName);
}
string[] IRepository.Get()
{
if (repo == null)
throw new InvalidOperationException($"{nameof(IRepositoryManager.Set)} must be called first.");
else
return repo.Get();
}
}
This solution certainly allows the controller to stay small, but in my experience, temporal coupling almost always hurts more than it helps. Also, it's unclear that these two lines in the controller have anything to do with each other:
repoManager.Set(repoName);
return businessLogic.Compute();
...but obviously they do. So this is a pretty bad solution.
Answer #5 - Inject the parameter-based dependency inside the controller
This solution makes the controller part of the composition root, rather than having it be resolved by dependency injection. (The line where the built container is retrieved could be done in other ways, but that's not the important part - the main idea is that we need to access its BeginLifetimeScope method directly after we have the input parameters.)
public class SelfAwareDIController : ApiController
{
public SelfAwareDIController() { }
public IEnumerable<string> Get(string repoName)
{
var container = (AutofacWebApiDependencyResolver)GlobalConfiguration.Configuration.DependencyResolver;
using (var scope = container.Container.BeginLifetimeScope(builder =>
builder.RegisterInstance(new Input { RepoName = repoName }).AsSelf()))
{
var businessLogic = scope.Resolve<IBusinessLogic>();
return businessLogic.Compute();
}
}
}
This solution avoids temporal coupling (since businessLogic cannot exist outside the lifetime scope where it can be resolved). It also allows us to remove the REPOSITORY RESOLVER; I was already uncomfortable with REPOSITORY RESOLVER because it's an expansion of the Composition Root that interferes with the DI container's centralized handling of object creation. A downside is that it moves some of the container-related code into the controller rather than keeping it all in the service configuration. (Again, in a non-trivial example there may be many controllers that need to implement similar logic.) It also prevents the controller itself from being instantiated by the DI container (which you can do with AutoFac.WebApi2 package). Still, because it restricts the knowledge of this new context to the controller (and removes the necessity of having a factory class), this is probably the least objectionable of the solutions that I've identified.

Way to dynamically get repositories without a dependency on a DI container

I have a class that returns a repository (read only) using a generic method this is to reduce the number of repository classes I need to inject into classes in my business layer. It also allows me to add and use a new repo anywhere I have this wrapper class simply by adding a repo which implements IGenericReadRepo<T> as this will be registered in unity using the line Container.RegisterType(typeof(IGenericReadRepository<>), typeof(GenericReadRepository<>), new TransientLifetimeManager());. However this has is dependent on unity being the DI container. This smells to me.
public class ReadRepositoryWrapper : IReadRepositoryWrapper
{
private IUnityContainer _unityContainer;
public ReadRepositoryWrapper(IUnityContainer container)
{
_unityContainer = container;
}
public IGenericReadRepository<T> GetReadRepository<T>() where T : class
{
return _unityContainer.Resolve<IGenericReadRepository<T>>();
}
}
Can anyone think of a way to implement the GetReadRepository<T> without a the dependency on unity while not introducing any new dependencies. Or can someone think of another way to get repositories without having bloated constructors or a dependency on my context.
You can create generic factory interfaces/classes for dynamic object creation. Many DI containers support object creation using lambda expressions.
public interface IFactory<T>
{
T Create();
}
public class Factory<T> : IFactory<T>
{
private readonly Func<T> _creator;
public Factory(Func<T> creator)
{
if(creator == null)
throw new ArgumentNullException("creator");
_creator = creator;
}
public T Create()
{
return _creator();
}
}
The generic factory interface than can be injected into the consuming classes.
public class ReadRepositoryWrapper<T> : IReadRepositoryWrapper<T> where T : class
{
private readonly IFactory<IGenericReadRepository<T>> _factory;
public ReadRepositoryWrapper(IFactory<IGenericReadRepository<T>> factory)
{
if(factory == null)
throw new ArgumentNullException("factory");
_factory = factory;
}
public IGenericReadRepository<T> GetReadRepository()
{
return _factory.Create();
}
}
Or something like that.

Ninject Contextual Binding at runtime depending on a specific value [duplicate]

If I have the following code:
public class RobotNavigationService : IRobotNavigationService {
public RobotNavigationService(IRobotFactory robotFactory) {
//...
}
}
public class RobotFactory : IRobotFactory {
public IRobot Create(string nameOfRobot) {
if (name == "Maximilian") {
return new KillerRobot();
} else {
return new StandardRobot();
}
}
}
My question is what is the proper way to do Inversion of Control here? I don't want to add the KillerRobot and StandardRobot concretes to the Factory class do I? And I don't want to bring them in via a IoC.Get<> right? bc that would be Service Location not true IoC right? Is there a better way to approach the problem of switching the concrete at runtime?
For your sample, you have a perfectly fine factory implementation and I wouldn't change anything.
However, I suspect that your KillerRobot and StandardRobot classes actually have dependencies of their own. I agree that you don't want to expose your IoC container to the RobotFactory.
One option is to use the ninject factory extension:
https://github.com/ninject/ninject.extensions.factory/wiki
It gives you two ways to inject factories - by interface, and by injecting a Func which returns an IRobot (or whatever).
Sample for interface based factory creation: https://github.com/ninject/ninject.extensions.factory/wiki/Factory-interface
Sample for func based: https://github.com/ninject/ninject.extensions.factory/wiki/Func
If you wanted, you could also do it by binding a func in your IoC Initialization code. Something like:
var factoryMethod = new Func<string, IRobot>(nameOfRobot =>
{
if (nameOfRobot == "Maximilian")
{
return _ninjectKernel.Get<KillerRobot>();
}
else
{
return _ninjectKernel.Get<StandardRobot>();
}
});
_ninjectKernel.Bind<Func<string, IRobot>>().ToConstant(factoryMethod);
Your navigation service could then look like:
public class RobotNavigationService
{
public RobotNavigationService(Func<string, IRobot> robotFactory)
{
var killer = robotFactory("Maximilian");
var standard = robotFactory("");
}
}
Of course, the problem with this approach is that you're writing factory methods right inside your IoC Initialization - perhaps not the best tradeoff...
The factory extension attempts to solve this by giving you several convention-based approaches - thus allowing you to retain normal DI chaining with the addition of context-sensitive dependencies.
The way you should do:
kernel.Bind<IRobot>().To<KillingRobot>("maximilliam");
kernel.Bind<IRobot>().To<StandardRobot>("standard");
kernel.Bind<IRobotFactory>().ToFactory();
public interface IRobotFactory
{
IRobot Create(string name);
}
But this way I think you lose the null name, so when calling IRobotFactory.Create you must ensure the correct name is sent via parameter.
When using ToFactory() in interface binding, all it does is create a proxy using Castle (or dynamic proxy) that receives an IResolutionRoot and calls the Get().
I don't want to add the KillerRobot and StandardRobot concretes to the Factory class do I?
I would suggest that you probably do. What would the purpose of a factory be if not to instantiate concrete objects? I think I can see where you're coming from - if IRobot describes a contract, shouldn't the injection container be responsible for creating it? Isn't that what containers are for?
Perhaps. However, returning concrete factories responsible for newing objects seems to be a pretty standard pattern in the IoC world. I don't think it's against the principle to have a concrete factory doing some actual work.
I was looking for a way to clean up a massive switch statement that returned a C# class to do some work (code smell here).
I didn't want to explicitly map each interface to its concrete implementation in the ninject module (essentially a mimic of lengthy switch case, but in a diff file) so I setup the module to bind all the interfaces automatically:
public class FactoryModule: NinjectModule
{
public override void Load()
{
Kernel.Bind(x => x.FromThisAssembly()
.IncludingNonPublicTypes()
.SelectAllClasses()
.InNamespaceOf<FactoryModule>()
.BindAllInterfaces()
.Configure(b => b.InSingletonScope()));
}
}
Then create the factory class, implementing the StandardKernal which will Get the specified interfaces and their implementations via a singleton instance using an IKernal:
public class CarFactoryKernel : StandardKernel, ICarFactoryKernel{
public static readonly ICarFactoryKernel _instance = new CarFactoryKernel();
public static ICarFactoryKernel Instance { get => _instance; }
private CarFactoryKernel()
{
var carFactoryModeule = new List<INinjectModule> { new FactoryModule() };
Load(carFactoryModeule);
}
public ICar GetCarFromFactory(string name)
{
var cars = this.GetAll<ICar>();
foreach (var car in cars)
{
if (car.CarModel == name)
{
return car;
}
}
return null;
}
}
public interface ICarFactoryKernel : IKernel
{
ICar GetCarFromFactory(string name);
}
Then your StandardKernel implementation can get at any interface by the identifier of you choice on the interface decorating your class.
e.g.:
public interface ICar
{
string CarModel { get; }
string Drive { get; }
string Reverse { get; }
}
public class Lamborghini : ICar
{
private string _carmodel;
public string CarModel { get => _carmodel; }
public string Drive => "Drive the Lamborghini forward!";
public string Reverse => "Drive the Lamborghini backward!";
public Lamborghini()
{
_carmodel = "Lamborghini";
}
}
Usage:
[Test]
public void TestDependencyInjection()
{
var ferrari = CarFactoryKernel.Instance.GetCarFromFactory("Ferrari");
Assert.That(ferrari, Is.Not.Null);
Assert.That(ferrari, Is.Not.Null.And.InstanceOf(typeof(Ferrari)));
Assert.AreEqual("Drive the Ferrari forward!", ferrari.Drive);
Assert.AreEqual("Drive the Ferrari backward!", ferrari.Reverse);
var lambo = CarFactoryKernel.Instance.GetCarFromFactory("Lamborghini");
Assert.That(lambo, Is.Not.Null);
Assert.That(lambo, Is.Not.Null.And.InstanceOf(typeof(Lamborghini)));
Assert.AreEqual("Drive the Lamborghini forward!", lambo.Drive);
Assert.AreEqual("Drive the Lamborghini backward!", lambo.Reverse);
}

Initializing objects using configuration file at runtime

I currently writing a project that need to generate different type of object, base on XML configuration file.
Each object that generated is instance of an IProvidor interface and and needs to contain several pre-processing, and handling methods that defined by the XML configuration file.
I generated different factories classes for:
creating the Provider (which implement the IProvider interface)
creating the Pre-Processing operation (I have IPreProcessor interface that all preProcessor class need to implement.
the same thing for handling methods (IHandler interface being implemented by several classes).
Question
How can I combine all of this into one object in runtime?
Olivier Jacot-Desc is absolutely on the right track (+1 for that). The only thing missing from his answer is loading the correct implementations from the configuration.
There are a lot of ways of doing this, for instance by storing the type name in the configuration, but you can also go for a simpler approach, such as storing a simple boolean in the configuration.
IProvider providerX = GetProviderFromConfig();
IHandler handlerZ = GetHandlerFromConfig();
IPreProcessor preProcessorY = GetProcessorFromConfig();
var provider =
new ProviderWrapper(providerX, preProcessorY, handlerZ);
private static IProvider GetProviderFromConfig()
{
if (ConfigurationManager.AppSettings["provider"] == "mail")
{
return new MailProvider();
}
else
{
return new FtpProvider();
}
}
// implement GetHandlerFromConfig just like
// the GetProvider.
UPDATE
When you have many types to switch between, storing the name of the type might be a better choice:
private static IProvider GetProviderFromConfig()
{
string typeName =
ConfigurationManager.AppSettings["provider"];
Type providerType = Type.GetType(typeName);
return (IProvider)
Activator.CreateInstance(providerType);
}
UPDATE 2
Here is an example of how to configure this with a DI Container. I'm using Simple Injector (with extensions), but any container will do (although the way to configure it will differ per container):
Registration:
using SimpleInjector;
using SimpleInjector.Extensions;
Type providerType = Type.GetType(
ConfigurationManager.AppSettings["provider"]);
Type handlerType = Type.GetType(
ConfigurationManager.AppSettings["handler"]);
Type processorType = Type.GetType(
ConfigurationManager.AppSettings["preProcessor"]);
var container = new Container();
container.Register(typeof(IProvider), providerType);
container.Register(typeof(IHandler), handlerType);
container.Register(typeof(IPreProcessor), processorType);
Resolving a provider:
var provider = container.GetInstance<IPovider>();
Tip: If you use constructor injection, you don't have to wire the types by hand, the container will do this for you. For instance, when your MailProvider looks like this, the container is able to inject the needed dependencies (IHandler, and IPreProcessor) through the constructor:
public class MailProvider : IProvider
{
private readonly IHandler handler;
private readonly IPreProcessor preProcessor;
public MailProvider(IHandler handler,
IPreProcessor preProcessor)
{
this.handler = handler;
this.preProcessor = preProcessor;
}
public void SomeAction() { ... }
}
I would create a wrapper class which implements these interfaces and inject the functionality.
Example interfaces
public interface IProvider
{
string ProvideSomething(int id);
}
public interface IPreProcessor
{
void PreProcess(string parameter);
}
public interface IHandler
{
void HandleSomething();
}
The wrapper would implement all of these interfaces
public class ProviderWrapper : IProvider, IPreProcessor, IHandler
{
private IProvider _provider;
private IPreProcessor _preProcessor;
private IHandler _handler;
public ProviderWrapper(IProvider provider, IPreProcessor preProcessor, IHandler handler)
{
_provider = provider;
_preProcessor = preProcessor;
_handler = handler;
}
#region IProvider Members
public string ProvideSomething(int id)
{
return _provider.ProvideSomething(id);
}
#endregion
#region IPreProcessor Members
public void PreProcess(string parameter)
{
_preProcessor.PreProcess(parameter);
}
#endregion
#region IHandler Members
public void HandleSomething()
{
_handler.HandleSomething();
}
#endregion
}
Now, you can instantiate a ProviderWrapper with the required functionality according to the configuration file and combine different the interface implementations.
var provider = new ProviderWrapper(providerX, preProcessorY, handlerZ);
Perhaps you could create instances of all of these classes as you would normally at runtime, then serialize them to xml. Then when you want to load your "configuration" you just need to de-serialize.
See here for serialization.

Configuring an Autofac delegate factory that's defined on an abstract class

I'm working on a C# project. I'm trying to get rid of a Factory class that has a large switch statement.
I want to configure Autofac to be able to construct a dependency based on a parameter, thereby allowing Autofac to take the place of the Factory.
I've looked at the DelegateFactories page of the Autofac wiki, but I can't figure out how to apply the pattern to an abstract class. Here's some code showing the situation:
public enum WidgetType
{
Sprocket,
Whizbang
}
public class SprocketWidget : Widget
{
}
public class WhizbangWidget : Widget
{
}
public abstract class Widget
{
public delegate Widget Factory(WidgetType widgetType);
}
public class WidgetWrangler
{
public Widget Widget { get; private set; }
public WidgetWrangler(IComponentContext context, WidgetType widgetType)
{
var widgetFactory = context.Resolve<Widget.Factory>();
Widget = widgetFactory(widgetType);
}
}
I'd like it if I were to say new WidgetWrangler(context, WidgetType.Sprocket), its Widget property would be a SpocketWidget.
When I try this, I get errors stating that Widget.Factory is not registered. Does this delegate factory pattern not work with abstract classes, and if so, is there another way to accomplish this?
What you're looking for is the IIndex<,> Relationship Type.
If you register your sub-classes with .Keyed<>(...) you can key a registration to a value (object).
For example:
builder.RegisterType<SprocketWidget>()
.Keyed<Widget>(WidgetType.Sproket)
.InstancePerDependency();
builder.RegisterType<WhizbangWidget>()
.Keyed<Widget>(WidgetType.Whizbang)
.InstancePerDependency();
Then you only require a dependency of IIndex<WidgetType,Widget> to mimic factory behaviour.
public class SomethingThatUsesWidgets
{
private readonly IIndex<WidgetType,Widget> _widgetFactory;
public SomethingThatUsesWidgets(IIndex<WidgetType,Widget> widgetFactory)
{
if (widgetFactory == null) throw ArgumentNullException("widgetFactory");
_widgetFactory = widgetFactory;
}
public void DoSomething()
{
// Simple usage:
Widget widget = widgetFactory[WidgetType.Whizbang];
// Safe Usage:
Widget widget2 = null;
if(widgetFactory.TryGetValue(WidgetType.Sprocket, out widget2))
{
// do stuff
}
}
}
That's using Dependency Injection approach, if you just want to resolve the factory:
var factory = Container.Resolve<IIndex<WidgetType,Widget>>();

Categories

Resources