Is it possible for autofac to create a generic factory that can only resolve types of a specific base class?
I’m currently seeing how feasible it is to retrofit a ‘brownfield’ c# project to use autofac. The project requires creating a tree of components of differing types but of the same base class. These components require authentication and database services (among other things) so it makes it hard to just have empty constructors.
So the factory would be so a user can create objects deriving a base class, use autofac to scan for these classes, and provide a factory for them. I thought it might make it easier to build component object trees if you didn’t have to provide factories for each class.
As an aside, or is this a sign of bad design? Should the components and the tree do as little as possible and we pass this tree to other services to provide processing and rendering?
Something like (where ? is the mystery factory)
public MyBase {
public Add(MyBase x) {..}
}
public DerivedA: MyBase {}
public DerivedB : MyBase {}
public DerivedC : DerivedA {}
public SomethingElse
{
private ? _myBaseFact;
public SomethingElse(? myBaseFact) {
_myBaseFact = myBaseFact;
}
public BuildComponentTree() {
DerivedA a = _myBaseFact<DerivedA>();
DerivedB b = _myBaseFact<DerivedB>();
DerivedC c = _myBaseFact<DerivedC>();
a.Add(b);
b.Add(c);
}
}
edit: I have been asked for a more concrete example, which is fair 🙂 There are framework components and I wanted to allow for the developers to create their own components without having to register with autofac. Having a factory class would mean that the developer would have to add their custom components to this factory right? Please excuse the example, this is similar to how the framework works when I encountered it.
FwComponent {
public FwComponent (DataProvider, AuthManager, OtherModule)
public Add(FwComponent x);
public Setup();
public Process();
public Render();
}
Page : FwComponent {
public Page(DataProvider, AuthManager, OtherModule): base(..)
public string Title;
...
}
Input: FwComponent {
public Input(DataProvider, AuthManager, OtherModule): base(..)
public string Name;
public int length;
...
}
Button: FwComponent {
public Button(DataProvider, AuthManager, OtherModule): base(..)
public string Name;
...
}
----
MyCustomButton : Button {
public MyCustomButton(DataProvider, AuthManager, OtherModule): base(..)
}
MyPersonalPage : FwComponent {
IContext _container;
public MyPersonalPage(DataProvider, AuthManager, OtherModule, IContext container): base(..)
public Setup() {
var input = _container.Resolve<Input>();
input.Name = 'xxx';
input.length = 10;
Add(input);
var butt = _container.Resolve<MyCustomButton>();
butt.name = "xxx";
Add(butt);
}
public Process() {
DataProvider.DoStuff();
}
}
In the code sample you gave, you seem to request for a specific type using
_myBaseFact<DerivedA>()and_myBaseFact<DerivedB>(). It’s hard to see what you are trying to accomplish, but this seems like a code smell to me, because you still have a dependency on the concrete types.As I see it you have two choices: Either you inject a factory and abstract away the derived types, -or- you directly inject the derived types into the constructor. Using a factory is useful in two scenario’s:
1: You have some sort of (not type based) argument that allows the factory to identify the returned type, as shown in the following example:
2: Your factory has multiple factory methods:
Note that both factory methods return a
MyBaseand never the specific type. The whole idea about polymorphism is that you shouldn’t care about the concrete type.IMO it doesn’t matter whether Autofac could create a factory for you or not. You shouldn’t rely on framework specific constructs like that, but depend on good application design. If you go for the factory approach, define an interface for that factory and inject an instance based on that interface. This makes the design very clean and it communicates it’s intend very nicely.