I would definitely use Delegate Factories to avoid having a dependency on the IoC container itself. By using Keyed Service Lookup, your code / factories will be tightly coupled to Autofac.
Here is nice and clean example, without having any dependency on Autofac:
Strategies:
public interface IStrategy { void Do(); }
public class ConcreteStrategyA : IStrategy { public void Do() { Console.WriteLine("Called ConcreteStrategyA.Do()"); } };
public class ConcreteStrategyB : IStrategy { public void Do() { Console.WriteLine("Called ConcreteStrategyB.Do()"); } };
The enum you want to switch on:
public enum ESomeEnum
{
UseStrategyA,
UseStrategyB,
}
The context which consumes the strategies:
private readonly Func<ESomeEnum, IStrategy> _strategyFactory;
public Context(Func<ESomeEnum, IStrategy> strategyFactory)
{
_strategyFactory = strategyFactory;
}
public void DoSomething()
{
_strategyFactory(ESomeEnum.UseStrategyB).Do();
_strategyFactory(ESomeEnum.UseStrategyA).Do();
}
And finally the container configuration:
var builder = new ContainerBuilder();
builder.RegisterType<Context>().AsSelf().SingleInstance();
builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(IStrategy)))
.Where(t => typeof(IStrategy).IsAssignableFrom(t))
.AsSelf();
builder.Register<Func<ESomeEnum, IStrategy>>(c =>
{
var cc = c.Resolve<IComponentContext>();
return (someEnum) =>
{
switch (someEnum)
{
case ESomeEnum.UseStrategyA:
return cc.Resolve<ConcreteStrategyA>();
case ESomeEnum.UseStrategyB:
return cc.Resolve<ConcreteStrategyB>();
default:
throw new ArgumentException();
}
};
});
var container = builder.Build();
container.Resolve<Context>().DoSomething();
If the strategies don't consume any dependencies that are registered in your container, you can new them up yourself, and simplify your configuration like this:
var builder = new ContainerBuilder();
builder.RegisterType<Context>().AsSelf().SingleInstance();
builder.Register<Func<ESomeEnum, IStrategy>>(c => StrategyFactory.GetStrategy);
var container = builder.Build();
container.Resolve<Context>().DoSomething();
And have the switch case in a seperate class:
public static class StrategyFactory
{
internal static IStrategy GetStrategy(ESomeEnum someEnum)
{
switch (someEnum)
{
case ESomeEnum.UseStrategyA:
return new ConcreteStrategyA();
case ESomeEnum.UseStrategyB:
return new ConcreteStrategyB();
default:
throw new ArgumentException();
}
}
}
Full running code example - check in .NET Fiddle:
using Autofac;
using System;
using System.Reflection;
namespace Samples.Autofac.StrategyPattern
{
public interface IStrategy { void Do(); }
public class ConcreteStrategyA : IStrategy { public void Do() { Console.WriteLine("Called ConcreteStrategyA.Do()"); } };
public class ConcreteStrategyB : IStrategy { public void Do() { Console.WriteLine("Called ConcreteStrategyB.Do()"); } };
public enum ESomeEnum
{
UseStrategyA, UseStrategyB,
}
public class Context
{
private readonly Func<ESomeEnum, IStrategy> _strategyFactory;
public Context(Func<ESomeEnum, IStrategy> strategyFactory)
{
_strategyFactory = strategyFactory;
}
public void DoSomething()
{
_strategyFactory(ESomeEnum.UseStrategyB).Do();
_strategyFactory(ESomeEnum.UseStrategyA).Do();
}
}
public class AutofacExample
{
public static void Main()
{
var builder = new ContainerBuilder();
builder.RegisterType<Context>().AsSelf().SingleInstance();
builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(IStrategy)))
.Where(t => typeof(IStrategy).IsAssignableFrom(t))
.AsSelf();
builder.Register<Func<ESomeEnum, IStrategy>>(c =>
{
var cc = c.Resolve<IComponentContext>();
return (someEnum) =>
{
switch (someEnum)
{
case ESomeEnum.UseStrategyA:
return cc.Resolve<ConcreteStrategyA>();
case ESomeEnum.UseStrategyB:
return cc.Resolve<ConcreteStrategyB>();
default:
throw new ArgumentException();
}
};
});
var container = builder.Build();
container.Resolve<Context>().DoSomething();
}
}
}