My configuration for a calculator dependent on its' View (GUI) is defined like so (it is then Resolved in the current context):
Dependencies.register<IView, View>(
"standardView"
);
//Register: calculator release configuration
Dependencies.register<ICalculator, Calculator>(
"releaseCalculator",
(new InjectionProperty(
"IView",
Dependencies.resolve<IView>("standardView")
))
);
//Resolve:
Calculator theCalculator = (Calculator)Dependencies.resolve<ICalculator>(
"releaseCalculator"
);
Where Dependencies is a wrapper for an IUnityContainer.
The injection-point in Calculator is:
private IView view;
[Dependency]
public IView IView{
get{return view;}
set{view = value;}
}
If you wish to see the definition for Dependencies please note that it is absolutely equivalent to a projection of unity container except I have extended direct control on lifetime-managers.
The problem is simply; given the above setup, the Property IView resolves to null at run-time. It is simply as though Unity just doesn't bloody work.
#Haukinger here is the wrapper:
using System.Collections.Generic;
using Unity;
using Unity.Lifetime;
using Unity.Registration;
namespace Calculator.Utils
{
public static class Dependencies
{
private static IUnityContainer graph;
private static List<KeyValuePair<string, LifetimeManager>> lifetimeManagers;
static Dependencies(){
//container
graph = new UnityContainer();
//instance managers 1 per dependency instance (implementor)
lifetimeManagers = new List<KeyValuePair<string, LifetimeManager>>();
}
//STATES:
public static void register<I, P>(string alias, params InjectionMember[] injections)
{
ContainerControlledTransientManager newLM = new ContainerControlledTransientManager();
lifetimeManagers.Add(new KeyValuePair<string, LifetimeManager>(
alias,
newLM
));
graph.RegisterType(
typeof(I),
typeof(P),
alias,
newLM,
injections
);
}
//function is identitical to Resolve
public static T resolve<T>(string alias)
{
return (T)graph.Resolve(typeof(T), alias);
}
public static void dispose(string alias)
{
LifetimeManager target = (ContainerControlledTransientManager)lifetimeManagers.Find((elem)=>(elem.Key.Equals(alias))).Value;
target.Dispose();
}
}
}
Named registrations are only injected when you request all registered types, i.e. IView[] allViews. If you request only one instance, you'll receive the default registration, in your case just null as you have no default registration.
Remove the name (standardView) and pass null as parameter name to RegisterType and you're good to go.
EDIT: this code works fine at my machine
internal class Program
{
static void Main( string[] args )
{
var container = new UnityContainer();
container.RegisterType<IDependency, MyDependency>((string)null);
var resolved = container.Resolve<Consumer>();
// resolved.Dependency is an instance of MyDependency
}
}
internal class Consumer
{
[Dependency]
public IDependency Dependency { get; set; }
}
public interface IDependency
{
}
internal class MyDependency : IDependency
{
}
Related
In a .NET Core 3.1 console application I want a Class that would have some parameters in constructor injected but some that I could assign manually. For example something like that but with IConfiguration Injected:
static void Main() {
var myObj1 = new MyClass(1);
var myObj2 = new MyClass(2);
}
public class MyClass {
public MyClass(IConfiguraiton config, int myVal)
{
}
}
I tried this with Ninject:
static void Main()
{
kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
kernel.Get<MyClass>();
}
public class MyClass
{
public MyClass(IConfiguraiton config)
{
}
}
public class Bindings : NinjectModule
{
public override void Load()
{
var configuration = new ConfigurationBuilder().AddJsonFile($"appsettings.json").Build();
Bind<IConfiguration>().ToMethod(ctx => SetupConfiguration()).InSingletonScope();
Bind<MyClass>().ToSelf().InTransientScope();
}
}
I managed to make simple dependency injection, but haven't had any success making injection with parameters.
I've read a lot of people suggesting that it's better to pass parameters into methods of the class rather than constructor, however in my situation this isn't an option in addition I'm a software engineering student, and would like to learn how to do this, since it might be useful in some situations.
This is a situation where the Ninject.Extensions.Factory is useful, as it is made exactly for this situation. It does pull in the Factory dependency in addition to Castle.Core, as it uses DynamicProxy under the hood (as a SE student, playing with this library is a good idea for using the interceptor pattern).
To use it, you define a Factory interface like so:
public interface IMyClassFactory
{
MyClass Create(int myVal);
}
Note that the Create method returns MyClass, and the argument(s) to the Create method match exactly in type and name to the arguments you wish to provide. The argument type(s) you want injected must be registered with the kernel. Unfortunately, it is easy to make a mistake here - if you specify a parameter that does not exist in the factory interface it is ignored, but if you forget one it will throw an exception when called.
Next, register IMyClassFactory like this: Bind<IMyClassFactory>().ToFactory(); and remove your binding for MyClass. Then wherever you need to create an instance, inject IMyClassFactory and call Create: kernel.Get<IMyClassFactory>().Create(2)
You can achieve the same result without using Ninject.Extensions.Factory by writing and registering your own implementation of IMyClassFactory, essentially doing the same thing that the code the Factory extension ends up emitting. A full sample is below using both methods based on commenting in/out the registration (note the output if you add .InSingletonScope() to the registration of IConfiguraiton - both approaches respect the binding scopes of Ninject).
internal class Program
{
static void Main(string[] args)
{
var kernel = new StandardKernel();
kernel.Bind<IConfiguraiton>().To<Configuraiton>();
kernel.Bind<IMyClassFactory>().ToFactory();
//kernel.Bind<IMyClassFactory>().To<NinjectMyClassFactory>().InSingletonScope();
var factory = kernel.Get<IMyClassFactory>();
var one = factory.Create(1);
var two = factory.Create(2);
}
}
public interface IMyClassFactory
{
MyClass Create(int myVal);
}
public class NinjectMyClassFactory : IMyClassFactory
{
public NinjectMyClassFactory(IResolutionRoot resolutionRoot)
{
ResolutionRoot = resolutionRoot;
}
private IResolutionRoot ResolutionRoot { get; }
public MyClass Create(int myVal)
{
return ResolutionRoot.Get<MyClass>(new ConstructorArgument("myVal", myVal));
}
}
public class MyClass
{
public MyClass(IConfiguraiton config, int myVal)
{
Console.Out.WriteLine("Created MyClass({0},{1})", config.MyNum, myVal);
}
}
public interface IConfiguraiton { int MyNum { get; } }
public class Configuraiton : IConfiguraiton
{
static int CreateCount;
public Configuraiton()
{
MyNum = Interlocked.Increment(ref CreateCount);
}
public int MyNum { get; }
}
I have to write a Complex calculator logic which has 4 different components to be calculated brokerage, stockprice, admin charges & other charges. Each having a different logic and formulas.
So I decided to use Unity DI. I have a ContainerFactoryClass which resolves all classes which implements IChargeCalculator interface as shown below in the TotalAnnualCostCalculator constructor.
public class TotalAnnualCostCalculator
{
private readonly IUnityContainer container;
//Constructor
public TotalAnnualCostCalculator()
{
container = ContainerFactory.InitializeContainer();
ContainerFactory.SetupContainer(container);
}
public AnnualCostCharges CalculateTotalAnnualCost(Parameters product)
{
var calculators = container.ResolveAll<ICalculator>().ToList();
// Invoke calcualtion method
Parallel.ForEach(calculators, c =>
{
return c.CalculateAnnualCost(product);
});
}
}
Container Factory class:-
public static class ContainerFactory
{
public static IUnityContainer Container { get; private set; }
public static IUnityContainer InitializeContainer()
{
var container = new UnityContainer();
RegisterDependencies(container);
return container;
}
private static void RegisterDependencies(UnityContainer container)
{
container.RegisterType<ICalculatorStrategyFactory, CalculatorStrategyFactory>("Factory");
container.RegisterType<IEffectiveAnnualCostCalculator, InvestmentManagementChargeCalculator>("IMCChargeCalculator",
new InjectionConstructor(new ResolvedParameter<ICalculatorStrategyFactory>("Factory")));
//container.RegisterType<IEffectiveAnnualCostCalculator, AdministrationChargeCalculator>("AdministrationChargeCalculator");
container.RegisterType<IEffectiveAnnualCostCalculator, AdviceChargeCalculator>("AdviceChargeCalculator");
container.RegisterType<IEffectiveAnnualCostCalculator, OtherChargeCalculator>("OtherChargeCalculator");
container.RegisterType<IInvestmentManagementChargeCalculator, LumpSumIMCCalculator>("LumpSumIMCCalculator");
container.RegisterType<IInvestmentManagementChargeCalculator, DebitOrderIMCCalculator>("DebitOrderIMCCalculator");
}
public static void SetupContainer(IUnityContainer container)
{
Container = container;
}
}
Then any API consumes my Calculator.dll by just creating an instance of TotalAnnualCostCalculator and call a method like this.
var totalCharges = calc.CalculateTotalAnnualCost(prod);
My code reviewer says its better to use Factory Pattern ,as this tightly coupled to Unity Framework.
Please advise
Indeed, don't use a DI Container at all. As Steven suggests in the comments, this seems a great fit for a Composite:
public class TotalAnnualCostCalculator : ICalculator
{
private readonly ICalculator[] calculators;
public TotalAnnualCostCalculator(params ICalculator[] calculators)
{
this.calculators = calculators;
}
public AnnualCostCharges CalculateTotalAnnualCost(Parameters product)
{
Parallel.ForEach(this.calculators, c => c.CalculateAnnualCost(product));
}
}
In the Composition Root, then, you simply new up all the ICalculator objects you'd like to use, and pass them to the constructor of TotalAnnualCostCalculator.
Register all IEffectiveAnnualCostCalculator (or what ever interface).
You just need to map the enumerable to an array of the same type.
container.RegisterType<IEnumerable<IEffectiveAnnualCostCalculator>, IEffectiveAnnualCostCalculator[]>();
Resolve with dependency injection:
private IEnumerable<IEffectiveAnnualCostCalculator> calculators;
public TotalAnnualCostCalculator(IEnumerable<IEffectiveAnnualCostCalculator> calculators)
{
this.calculators = calculators;
}
public AnnualCostCharges CalculateTotalAnnualCost(Parameters product)
{
Parallel.ForEach(this.calculators, c => c.CalculateAnnualCost(product));
}
When creating an application with Dependency Injection and it utilizes a framework for Dependency Injection such as Unity (or Ninject).
How do you initialize registering the interfaces to the container at the beginning all together and keep them available for the application to use throughout its running lifecycle of the application?
Do you need to pass the DI Container to each method that may utilize dependency injection, or is there some way to make the container globally accessible so that you can register them all together in the beginning and access them throughout running the application without having to continually pass them, and be able to utilize them when ever needed?
Environment: Visual Studio 2015, C#, Microsoft Unity (for DI Container)
Example Code
static void Main(string[] args)
{
// Make Unity resolve the interface, providing an instance
// of TrivialPursuit class
var diContainer = new UnityContainer();
diContainer.RegisterType<IGame, TrivialPursuit>();
var gameInstance = diContainer.Resolve<IGame>();
var xotherClass = new AnotherClass();
xotherClass.TestOtherClassOtherMethod();
}
------ Another class without context of the Dependency Injection Class ------
public void TestOtherClassOtherMethod()
{
IGame gameInstance = -- -Container is Not available to resolve from in this class ---
}
Reason: I don't want to need to pass every possible type that I may need later on to each class I load up, I will just want to use the instances when I need them. The more deeper I get into classes, later as the application becomes more complex, I won't want to pass down instances for each type up from the Main() method to each class.
A Dependency Injection (DI) container is just that. A framework for facilitating DI. You don't pass the container around in order to resolve instances of objects. You just request the type you need in your classes constructor and the DI framework will inject the appropriate dependency.
Mark Seemann has written a good book on dependency injection that I would recommend.
You register everything that'll need to be resolved with the container in the composition root. That is to say when your program starts up is when everything should be registered.
Let's say we have the following code:
public class MyClass
{
public Run()
{
var dependency = new Dependency1();
dependency.DoSomething();
}
}
public class Dependency1
{
public void DoSomething()
{
var dependency = new Dependency2();
dependeny.DoSomethingElse();
}
}
public class Dependency2
{
public void DoSomethingElse()
{
}
}
This gives us the above dependency chain: MyClass -> Dependency1 -> Dependency2.
The first thing we should do is refactor the classes to take their dependencies through their constructor and rely on interfaces rather than concretions. We can't inject dependencies unless there is a place to inject them (constructor, property, etc).
Here is the refactored code:
public interface IMyClass
{
void Run();
}
public interface IDependency1
{
void DoSomething();
}
public interface IDependency2
{
void DoSomethingElse();
}
public class MyClass : IMyClass
{
public readonly IDependency1 dep;
public MyClass(IDependency1 dep)
{
this.dep = dep;
}
public void Run()
{
this.dep.DoSomething();
}
}
public class Dependency1 : IDependency1
{
public readonly IDependency2 dep;
public MyClass(IDependency2 dep)
{
this.dep = dep;
}
public void DoSomething()
{
this.dep.DoSomethingElse();
}
}
public class Dependency2 : IDependency2
{
public void DoSomethingElse()
{
}
}
You'll notice the classes now all take their dependencies through their constructors and do not new up anything. Classes should only take in dependencies that they actually need. For example, MyClass does not NEED a Dependency2 so it doesn't ask for one. It only asks for a Dependency1 because that's all it needs. Dependency1 NEEDS Dependency2, not MyClass.
Now to wire it all up WITHOUT a container we would just new it all up in the composition root:
void Main()
{
var myClass = new MyClass(new Dependency1(new Dependency2()));
}
You can see how that could get cumbersom if we had tons of classes and depdencies. That's why we use a container. It handles all the depdency graph for us. With a container we'd rewrite it as follows:
void Main()
{
// the order of our registration does not matter.
var container = new Container();
container.Register<IDependency1>.For<Dependency1>();
container.Register<IDependency2>.For<Dependency2>();
container.Register<IMyClass>.For<MyClass>();
// then we request our first object like in the first example (MyClass);
var myClass = container.Resolve<IMyClass>();
myClass.Run();
}
In the second example the container will handle wiring up all the dependencies. So we never need to pass Depedency2 to MyClass and then to Depedency1. We only need to request it in Dependency1 and the container will wire it up for us like in the first example.
So in your example we would rewrite it like so:
static void Main(string[] args)
{
var game = new UnityContainer();
game.RegisterType<IGame, TrivialPursuit>();
game.RegisterType<IAnotherClass, AnotherClass>();
game.RegisterType<IYetAnotherClass, YetAnotherClass>();
var gameInstance = game.Resolve<IGame>();
// you'll need to perform some action on gameInstance now, like gameInstance.RunGame() or whatever.
}
public class Game : IGame
{
public Game(IAnotherClass anotherClass)
{
}
}
public class AnotherClass : IAnotherClass
{
public AnotherClass(IYetAnotherClass yetAnotherClass)
{
}
}
public class YetAnotherClass : IYetAnotherClass {}
In these cases there is no need to pass the container around. You register your dependencies with the container then request them in your classes constructors. If you wish to use the container in the class WITHOUT requesting it through the constructor then you are not doing DI you are just using the container as a singleton service locator. Something that should generally be avoided.
Container as a Service Locator
This should be generally avoided but if you want to use the container as a service locator you have two options:
1) Pass the container into your classes that need it through the constructor.
You can use the above examples for wiring your classes up for DI. But instead of requesting a dependency like IDependency in the constructor you just pass the container.
public class Game : IGame
{
public Game(IContainer container)
{
var blah = container.Resolve<IBlah>();
}
}
2) Request your container through a static class:
public static class ServiceLocator
{
private static IContainer container;
public static IContainer Container
{
get
{
if (container == null)
{
container = new Container();
}
return container;
}
}
}
Register everything as normal in your composition root using the ServiceLocator class. Then to use:
public class MyClass
{
public void DoSomething()
{
var blah = ServiceLocator.Container.Resolve<IBlah>();
}
}
UPDATE: Should I try to handle it by DI container or it's a wrong abstraction level here?
I would like to implement ABSTRACT FACTORY using MEF (.NET 4.5).
It doesn't work for me...
The composition remains unchanged. The changes were rejected because of the following error(s):
The composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information.
1) No exports were found that match the constraint:
ContractName Mef3.Factory
RequiredTypeIdentity Mef3.Factory
Resulting in: Cannot set import 'Mef3.Program._factory (ContractName="Mef3.Factory")' on part 'Mef3.Program'.
Element: Mef3.Program._factory (ContractName="Mef3.Factory") -->
Mef3.Program
Is it the right way to do it in MEF?
How can I forward id to Foo/Bar ctors?
The code:
class Program
{
static void Main(string[] args)
{
var program = new Program();
program.Run();
}
readonly CompositionContainer _container;
public Program()
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
_container = new CompositionContainer(catalog);
_container.ComposeParts(this);
}
[Import]
public Factory _factory;
public void Run()
{
var foo = _factory.GetInstance("foo", 123);
Console.WriteLine(foo is Foo);
}
}
[Export]
public class Factory
{
private readonly ExportFactory<Foo> _fooFactory;
private readonly ExportFactory<Bar> _barFactory;
[ImportingConstructor]
public Factory(ExportFactory<Foo> fooFactory, ExportFactory<Bar> barFactory)
{
_fooFactory = fooFactory;
_barFactory = barFactory;
}
public Base GetInstance(string name, int id)
{
switch (name)
{
case "foo":
return _fooFactory.CreateExport().Value;
case "bar":
return _barFactory.CreateExport().Value;
}
throw new ArgumentException();
}
}
public class Foo : Base
{
[ImportingConstructor]
public Foo([Import("Id")] int id)
{
}
}
public class Bar : Base
{
[ImportingConstructor]
public Bar([Import("Id")] int id)
{
}
}
[InheritedExport]
public abstract class Base
{
}
The issue looks to be caused by your [Import("Id")] on Foo and Bar. There is no export with a contract name of "Id". MEF in general doesn't allow you to pass in imports at runtime, you need to be able to satisfy the entire graph at composition time or else it will not work. If you wanted to use MEF to accomplish this particular scenario you should remove the ImportingConstructor on Foo and Bar and add a SetId method on the Base class and have your factory call it when you call GetInstance.
this is probably just a newbie question, but I have the following:
public class FooSettings {}
public class BarSettings {}
public class DohSettings {}
// There might be many more settings types...
public interface IProcessor { ... }
public class FooProcessor
: IProcessor
{
public FooProcessor(FooSettings) { ... }
}
public class BarProcessor
: IProcessor
{
public BarProcessor(BarSettings) { ... }
}
public class DohProcessor
: IProcessor
{
public DohProcessor(DohSettings) { ... }
}
// There might be many more processor types with matching settings...
public interface IProcessorConsumer {}
public class ProcessorConsumer
: IProcessorConsumer
{
public ProcessorConsumer(IProcessor processor) { ... }
}
An instance of either FooSettings or BarSettings is provided from an external source i.e.:
object settings = GetSettings();
And now I would like to resolve ProcessorConsumer based on injecting the existing instance of settings e.g.:
container.RegisterAssemblyTypes(...); // Or similar
container.Inject(settings);
var consumer = container.Resolve<IProcessorConsumer>();
That is if an instance of FooSettings is provided then a FooProcessor is created and injected into the ProcessorConsumer which is then the instance resolved.
I haven't been able to figure out how to do this in either StructureMap, Ninject nor Autofac... probably because I am a newbie when it comes to IoC containers. So answers for all of these or other containers so they can be compared would be highly appreciated.
UPDATE: I am looking for a solution which easily allows for new settings and processors to be added. Also there will be a one-to-on mapping from settings type to processor type. But which also allows for other instances/services to be injected in a given processor type, based on its constructor parameters. I.e. some processor might need a IResourceProvider service or similar. Just an example here.
Ideally, I would like something like
container.For<IProcessor>.InjectConstructorParameter(settings)
or similar. Thereby, guiding the IoC container to use the processor type matching the injected constructor parameter instance.
You don't want dependency injection for this. You want a factory (which, of course, you can build using your container). The factory would know how to take, say, an IProcessorSettings and return the appropriate IProcessor. In short, you can build a factory that uses the concrete type of an object that implements IProcessorSettings and the container to resolve an instance of the appropriate type.
I think what you are looking for is the ForObject() method in StructureMap. It can close an open generic type based on a given object instance. The key change you need to make to your design is to introduce the generic type:
public interface IProcessor { }
public interface IProcessor<TSettings> : IProcessor{}
All of the important stuff is still declared on IProcessor, the generic IProcessor<TSettings> is really just a marker interface. Each of your processors will then implement the generic interface, to declare which settings type they expect:
public class FooProcessor : IProcessor<FooSettings>
{
public FooProcessor(FooSettings settings) { }
}
public class BarProcessor : IProcessor<BarSettings>
{
public BarProcessor(BarSettings settings) { }
}
public class DohProcessor : IProcessor<DohSettings>
{
public DohProcessor(DohSettings settings) { }
}
Now, given an instance of a settings object, you can retrieve the correct IProcessor:
IProcessor processor = container.ForObject(settings).
GetClosedTypeOf(typeof(IProcessor<>)).
As<IProcessor>();
Now you can tell StructureMap to use this logic whenever it resolves an IProcessor:
var container = new Container(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.ConnectImplementationsToTypesClosing(typeof(IProcessor<>));
});
x.For<IProcessor>().Use(context =>
{
// Get the settings object somehow - I'll assume an ISettingsSource
var settings = context.GetInstance<ISettingsSource>().GetSettings();
// Need access to full container, since context interface does not expose ForObject
var me = context.GetInstance<IContainer>();
// Get the correct IProcessor based on the settings object
return me.ForObject(settings).
GetClosedTypeOf(typeof (IProcessor<>)).
As<IProcessor>();
});
});
StructureMap containers expose the Model property which allows you to query for the instances it contains.
var container = new Container(x =>
{
x.For<IProcessorConsumer>().Use<ProcessorConsumer>();
x.For<IProcessor>().Use(context =>
{
var model = context.GetInstance<IContainer>().Model;
if (model.PluginTypes.Any(t => typeof(FooSettings).Equals(t.PluginType)))
{
return context.GetInstance<FooProcessor>();
}
return context.GetInstance<BarProcessor>();
});
});
In Autofac given:
public class AcceptsTypeConstructorFinder
: IConstructorFinder
{
private readonly Type m_typeToAccept;
public AcceptsTypeConstructorFinder(Type typeToAccept)
{
if (typeToAccept == null) { throw new ArgumentNullException("typeToAccept"); }
m_typeToAccept = typeToAccept;
}
public IEnumerable<ConstructorInfo> FindConstructors(Type targetType)
{
return targetType.GetConstructors()
.Where(constructorInfo => constructorInfo.GetParameters()
.Select(parameterInfo => parameterInfo.ParameterType)
.Contains(m_typeToAccept));
}
}
the following works:
// Load
var settings = new BarSettings();
var expectedProcessorType = typeof(BarProcessor);
// Register
var constructorFinder = new AcceptsTypeConstructorFinder(settings.GetType());
var builder = new ContainerBuilder();
var assembly = Assembly.GetExecutingAssembly();
builder.RegisterInstance(settings);
builder.RegisterAssemblyTypes(assembly)
.Where(type => type.IsAssignableTo<IProcessor>() && constructorFinder.FindConstructors(type).Any())
.As<IProcessor>();
builder.RegisterAssemblyTypes(assembly)
.As<IProcessorConsumer>();
using (var container = builder.Build())
{
// Resolve
var processorConsumer = container.Resolve<IProcessorConsumer>();
Assert.IsInstanceOfType(processorConsumer, typeof(ProcessorConsumer));
Assert.IsInstanceOfType(processorConsumer.Processor, expectedProcessorType);
// Run
// TODO
}
However, I find this to be rather cumbersome and was hoping for something more built into an IoC container.
Now, I'm not saying this is the right way to do this. However, it may be another option if you are using Autofac. This assumes that you are happy for the registration delegate to call GetSettings at the point you try and resolve the IProcessorConsumer. If you are able to do that, you can do what you want in the registration, as below:
var cb = new ConatainerBuilder();
cb.Register(c =>
{
var settings = GetSettings();
if(settings is FooSettings)
return new FooProcessor((FooSettings)settings);
else if(settings is BarSettings)
return new BarProcessor((BarSettings)settings);
else
throw new NotImplementedException("Hmmm. Got some new fangled settings.");
}).As<IProcessor>();
//Also need to register IProcessorConsumer
Note: This code may be wrong as I can't try it right now.
Here is as close as you can get to a proper factory method. But there are some issues. First, here's the code; then we'll talk.
public class FooSettings
{
public int FooNumber { get; set; }
public string FooString { get; set; }
}
public class BarSettings
{
public int BarNumber { get; set; }
public string BarString { get; set; }
}
public interface IProcessor
{
void Process();
}
public class FooProcessor : IProcessor
{
public FooProcessor(FooSettings settings) { }
public void Process() { }
}
public class BarProcessor : IProcessor
{
public BarProcessor(BarSettings settings) { }
public void Process() { }
}
public interface IProcessorFactory
{
IProcessor GetProcessor(object settings);
}
public interface IProcessorConsumer { }
public class ProcessorConsumer : IProcessorConsumer
{
private IProcessorFactory _processorFactory;
private object _settings;
public ProcessorConsumer(IProcessorFactory processorFactory, object settings)
{
_processorFactory = processorFactory;
_settings = settings;
}
public void MyLogic()
{
IProcessor processor = _processorFactory.GetProcessor(_settings);
processor.Process();
}
}
public class ExampleProcessorFactory : IProcessorFactory
{
public IProcessor GetProcessor(object settings)
{
IProcessor p = null;
if (settings is BarSettings)
{
p = new BarProcessor(settings as BarSettings);
}
else if (settings is FooSettings)
{
p = new FooProcessor(settings as FooSettings);
}
return p;
}
}
So what's the issue? It's the different types of settings that you're giving to your factory method. Sometimes it's FooSettings and sometimes it's BarSettings. Later, it might be xxxSettings. Each new type will force a recompilation. If you had a common Settings class, this would not be the case.
The other issue? Your consumer gets passed the factory and the settings and uses that to get the correct processor. If you have someone passing these to your consumer, just have that entity call GetProcessor on the Factory and pass the resulting IProcessor to the consumer.
I think the issue is that you haven't actually specified in any structured way how to resolve a processor from a settings instance. How about making the settings object return the processor? That seems to be the right place to put this information:
public interface ISettings
{
IProcessor GetProcessor();
}
Each implementation must resolve its own processor implementation:
public class FooSettings : ISettings
{
//this is where you are linking the settings type to its processor type
public IProcessor GetProcessor() { return new FooProcessor(this); }
}
And any code needing a processor gets it from the settings object, which you can reference from the consumer constructor:
var consumer = new ProcessorConsumer(Settings.GetProcessor());