Configuring an Autofac delegate factory that's

2020-02-09 18:01发布

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?

1条回答
2楼-- · 2020-02-09 18:48

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>>();
查看更多
登录 后发表回答