简体   繁体   中英

Autofac: Registering Func<> or Factory?

I have to create implementations at runtime based on some messages/properties I receive from the server which also need to be transformed by the newly created object. I'm new to Autofac, but as far as I can see there are two approaches on how to solve this.

Approach 1: registering dedicated factories

...
builder.RegisterType<MTextField>().Keyed<IComponent>(typeof(TextFieldProperties));
builder.RegisterType<ComponentFactory>().As<IComponentFactory>();

public class ComponentFactory : IComponentFactory
{
    private readonly IIndex<Type, IComponent> _lookup;

    public ComponentFactory(IIndex<Type, IComponent> lookup)
    {
        _lookup = lookup;
    }

    public IComponent Create(ComponentProperties properties)
    {
        var component = _lookup[properties.GetType()];
        component.Transform(properties);
        return component;
    }
}

Approach 2: registering according funcs

...
builder.RegisterType<MTextField>().Keyed<IComponent>(typeof(TextFieldProperties));
builder.Register<Func<ComponentProperties, IComponent>>(c =>
{
    var context = c.Resolve<IComponentContext>();
    return properties =>
    {
        var component = context.ResolveKeyed<IComponent>(properties.GetType());
        component.Transform(properties);
        return component;
    };
});

Questions:

I think this might be a subjective thing but I wanted to ask anyway.

  • Which approach is preferable and why?
  • Is there even a better solution?
  • Is it really necessary to store the context in "Approach 2"?

EDIT

ok, i played a bit more with autofac. here's my current approach:

public class TransformerFactory<D, T> : ITransformFactory<D, T>
    where T : ITransform<D>
{
    private readonly IIndex<Type, T> _lookup;


    public TransformerFactory(IIndex<Type, T> lookup)
    {
        _lookup = lookup;
    }


    public T Create(D data, Action<T> prepareInstance = null)
    {
        var instance = _lookup[data.GetType()];
        if (prepareInstance != null)
        {
            prepareInstance(instance);
        }
        instance.Transform(data);
        return instance;
    }
}

builder.RegisterGeneric(typeof(TransformerFactory<,>)).As(typeof(ITransformFactory<,>)); 
// e.g. var x = container.Resolve<ITransformFactory<ComponentProperties, IComponent>>();

The first approach appears to be the preferable approach. The two reasons I offer are:

  1. Keyed and IIndex provide a sufficient and clean out-of-the-box solution to the task at hand. Whereas approach 2 is using a more generalized tool that requires additional logic on your part to work (ie you writing the code to call ResolveKeyed). If there's a simple purpose-specific solution, use that in preference to a more generalized solution.

  2. Approach 1 will be able to correctly manage lifetime and scopes. Approach 2, as you've raised, captures the context, and will resolve individual instances against that context. This means that the lifetime of individual instances will be based on the scope and life of the factory, rather than the lifetime policy specified for the individual services.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM