-
-
Save Rookian/2601765 to your computer and use it in GitHub Desktop.
class Program | |
{ | |
static void Main() | |
{ | |
ObjectFactory.Initialize(x => | |
{ | |
x.For<IExecuter>().Use<Executer>(); | |
x.For<IService>().Use<Service>(); | |
x.For<Func<Data, IExecuter>>().Use(data => ObjectFactory.With(data.GetType(), data).GetInstance<IExecuter>()); | |
}); | |
var consumer = ObjectFactory.GetInstance<FormularWindow>(); | |
consumer.InvokeExecuter(); | |
Console.ReadLine(); | |
} | |
} | |
public class Executer : IExecuter | |
{ | |
readonly Data _data; | |
readonly IService _service; | |
public Executer(Data data, IService service) | |
{ | |
_data = data; | |
_service = service; | |
} | |
public void Execute() | |
{ | |
Console.WriteLine("I consume the data object with id {0}", _data.Id); | |
_service.DoAnything(); | |
} | |
} | |
public class Service : IService | |
{ | |
public void DoAnything() | |
{ | |
Console.WriteLine("I do anything else"); | |
} | |
} | |
public class FormularWindow | |
{ | |
readonly Func<Data, IExecuter> _createExecuter; | |
// Mixing service dependencies and run time values in ctor | |
public FormularWindow(Func<Data, IExecuter> createExecuter) | |
{ | |
_createExecuter = createExecuter; | |
} | |
public void InvokeExecuter() | |
{ | |
var selectedData = GetSelectedData(); | |
var executer = _createExecuter(selectedData); | |
executer.Execute(); | |
} | |
private static Data GetSelectedData() | |
{ | |
return new Data { Id = 4, Description = "Test" }; | |
} | |
} | |
public class Data | |
{ | |
public int Id { get; set; } | |
public string Description { get; set; } | |
} | |
public interface IExecuter | |
{ | |
void Execute(); | |
} | |
public interface IService | |
{ | |
void DoAnything(); | |
} | |
############################################################################################################# | |
For me it seems there is no way of using an interface for the factory instead of a Func. And if you use the | |
factory you still end using Func in the factory. | |
############################################################################################################# | |
class Program | |
{ | |
static void Main() | |
{ | |
var container = new Container(); | |
container.Configure(x=> | |
{ | |
x.For<IService>().Use<Service>(); | |
x.For<IExecuterFactory>().Use<ExecuterFactory>(); | |
x.For<IExecuter>().Use<Executer>(); | |
x.For<Func<Data, IExecuter>>().Use(data => container.With(data.GetType(), data).GetInstance<IExecuter>()); | |
}); | |
var consumer = container.GetInstance<FormularWindow>(); | |
consumer.InvokeExecuter(); | |
Console.ReadLine(); | |
} | |
} | |
internal class ExecuterFactory : IExecuterFactory | |
{ | |
private readonly Func<Data, IExecuter> _createExecuter; | |
public ExecuterFactory(Func<Data, IExecuter> createExecuter) | |
{ | |
_createExecuter = createExecuter; | |
} | |
public IExecuter Create(Data data) | |
{ | |
return _createExecuter(data); | |
} | |
} | |
public interface IExecuterFactory | |
{ | |
IExecuter Create(Data data); | |
} | |
public class FormularWindow | |
{ | |
private readonly IExecuterFactory _executerFactory; | |
// Mixing service dependencies and run time values in ctor | |
public FormularWindow(IExecuterFactory executerFactory) | |
{ | |
_executerFactory = executerFactory; | |
} | |
public void InvokeExecuter() | |
{ | |
var selectedData = GetSelectedData(); | |
var executer = _executerFactory.Create(selectedData); | |
executer.Execute(); | |
} | |
private static Data GetSelectedData() | |
{ | |
return new Data { Id = 4, Description = "Test" }; | |
} | |
} |
// Toss in a matching interface, let the default conventions pick it up for you, and off you go.
public class SomethingFactory
{
private readonly IContainer _container;
public SomethingFactory(IContainer container)
{
_container = container;
}
public IExecutor Build(Data data)
{
return _container.With(data).GetInstance<IExecutor>();
}
}
yes thats an option too, but isn't that service location instead of dependency injection? Furthermore I have to reference StructureMap all over my projects :/ Maybe I am too unprogramtic.
With CastleWindsor you use dependency injection and you dont have to reference it all over your projects.
I understand the different between service location and dependency injection just fine and I helped develop the thinking around best practices for these things long before Mark Seeman wrote his book, but frankly, I see this as a very rare occurrence in my code. Having an occasional reference to the container in code has never been a problem in my experience.
Gotta ask though, why are you needing to do this often enough that you'd want the full abstraction in the container? I see this as an unimportant edge case.
My problem is that if you pass the container into other classes you do not see the real dependency. You only see that you depend on IContainer instead of IExecutor. Furthermore unit tests are coupled to StructureMap. Thats just my opinion.
I tried the CreateFactory method, but it seems not fully implemented. For now it is not possible to get a list of dependencies.
[Test]
public void Can_resolve_components()
{
container.Configure(cfg =>
{
cfg.For<IDummyService>().Use<Dummy1>();
cfg.For<IDummyService>().Use<Dummy2>();
cfg.For<IEnumerable<IDummyService>>().Use(container.GetAllInstances<IDummyService>());
cfg.For<IDummyFactory>().CreateFactory();
});
var factory = container.GetInstance<IDummyFactory>();
var components = factory.CreateDummyServices().ToList();
components.ShouldNotBeNull();
components.Count().ShouldBeTheSameAs(2);
}
Are some of you guys will continue to develope this feature for StructureMap?
I added the "list resolving" feature for AutoFactory with unit tests.
[Test]
public void Can_resolve_components()
{
container.Configure(cfg =>
{
cfg.For<IDummyService>().Use<Dummy1>();
cfg.For<IDummyService>().Use<Dummy2>();
cfg.For<IDummyFactory>().CreateFactory();
});
var factory = container.GetInstance<IDummyFactory>();
var components = factory.CreateDummyServices().ToList();
components.ShouldNotBeNull();
components.Contains(new Dummy1()).ShouldBeTrue();
components.Contains(new Dummy2()).ShouldBeTrue();
components.Count().ShouldEqual(2);
}
[Test]
public void Can_resolve_components_with_type()
{
container.Configure(cfg =>
{
cfg.Scan(s =>
{
s.AssemblyContainingType<MessageHandler2>();
s.ConnectImplementationsToTypesClosing(typeof (IHandler<>));
});
cfg.For<IDummyFactory>().CreateFactory();
});
var factory = container.GetInstance<IDummyFactory>();
var commandHandlerType = typeof (IHandler<Message>);
var components = factory.CreateHandlers(commandHandlerType).ToList();
components.ShouldNotBeNull();
components.Contains(new MessageHandler()).ShouldBeTrue();
components.Contains(new MessageHandler2()).ShouldBeTrue();
components.Count().ShouldEqual(2);
}
With CastleWindsor it is more easy. I can use an interface as a factory instead of the Func<>.