Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Rookian/2601765 to your computer and use it in GitHub Desktop.
Save Rookian/2601765 to your computer and use it in GitHub Desktop.
Ctor With Runtime Values And Service Dependencies
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" };
}
}
@Rookian
Copy link
Author

Rookian commented May 5, 2012

With CastleWindsor it is more easy. I can use an interface as a factory instead of the Func<>.

class Program
{
    static void Main()
    {
        var windsorContainer = new WindsorContainer();
        windsorContainer.AddFacility(new TypedFactoryFacility());
        windsorContainer.Register(Component.For<IExecuter>().ImplementedBy<Executer>(),
                                   Component.For<IService>().ImplementedBy<Service>(),
                                   Component.For<IExecuterFactory>().AsFactory(),
                                   Component.For<FormularWindow>().ImplementedBy<FormularWindow>());

        var consumer = windsorContainer.Resolve<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 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" };
    }
}

public class Data
{
    public int Id { get; set; }
    public string Description { get; set; }
}

public interface IExecuter
{
    void Execute();
}

public interface IService
{
    void DoAnything();
}

@jeremydmiller
Copy link

// 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>();
}

}

@Rookian
Copy link
Author

Rookian commented May 5, 2012

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.

@jeremydmiller
Copy link

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.

@Rookian
Copy link
Author

Rookian commented May 6, 2012

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?

@Rookian
Copy link
Author

Rookian commented May 7, 2012

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);
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment