views:

70

answers:

1

Why does .net MVC source code ControllerBuilder use a delegate to assign the controller factory?:

private Func<IControllerFactory> _factoryThunk;

public void SetControllerFactory(IControllerFactory controllerFactory) {
    _factoryThunk = () => controllerFactory;
}

Why can't it just assign the ControllerFactory directly?, ie:

private IControllerFactory _factory;

public void SetControllerFactory(IControllerFactory controllerFactory) {
    _factory = controllerFactory;
}

public void SetControllerFactory(Type controllerFactoryType) {
    _factory = (IControllerFactory)Activator.CreateInstance(controllerFactoryType);
}
+3  A: 

The reason that _factoryThunk is currently defined as a Func<IControllerFactory> is that it's a generic means to support both overloads:

void SetControllerFactory(Type);
void SetControllerFactory(IControllerFactory);

The implementation of the first one uses the fact that _factoryThunk is a Func by declaring that Func inline by using Activator to instantiate the Type lazily:

this._factoryThunk = delegate {
    IControllerFactory factory;
    try
    {
        factory = (IControllerFactory) Activator.CreateInstance(controllerFactoryType);
    }
    catch (Exception exception)
    {
        throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, MvcResources.ControllerBuilder_ErrorCreatingControllerFactory, new object[] { controllerFactoryType }), exception);
    }
    return factory;
};

Therefore, the reason the other overload looks like it has a spurious implementation is that since _factoryThunk is declared as a Func, the line you propose wouldn't have even compiled:

_factoryThunk = controllerFactory;

_factoryThunk is a Func<IControllerFactory> whereas controllerFactory is an IControllerFactory -- incompatible types.

Kirk Woll
The question is why do they need the lazy instantiation? The second method could be _factory = (IControllerFactory)Activator.CreateInstance(controllerFactoryType); I've updated the question to be clearer
JontyMC
@JontyMC, you're absolutely right, I missed that nuance before. After examining the source code a bit more, I believe the explanation for the design is to allow implementors of IControllerFactory to maintain state for a specific Controller that it instantiates. i.e. The design results in a 1-1 mapping between instances of a Controller and instances of their IControllerFactory. This way, the implementation of IControllerFactory could, for example, hang on to the instance of the Controller it instantiates in a field for later use. (not sure why you would want to though)
Kirk Woll