Vuoi che tutte le dipendenze vengano iniettate dal livello superiore assoluto, quindi dovresti avere un grafico di dipendenza con una radice e la radice ha un riferimento all'implementazione concreta dei deps in ogni nodo, registra quella concrezione per l'interfaccia in un contenitore, quindi afferra solo i bisogni di primo livello it dal contenitore. Ma nel fare ciò, quel livello ha deps i costrutti del contenitore che ha deps il costrutto del contenitore ...
Pensa al tuo grafico delle dipendenze costruito dal contenitore in questo modo:
public void main()
{
var frmDisplayStock = new FrmDisplayStock(
new Stock(
new DataStock()
)
);
}
Tranne che invece di costruire manualmente ciascuna dipendenza su ogni livello del grafico, devi solo registrare i tipi con un contenitore (o comunque il contenitore che scegli ti richiede di registrarli). Ad esempio:
public void main()
{
var container = new SomeIocContainer();
container.Register<IDataStock>(typeof(DataStock));
container.Register<IStock>(typeof(Stock));
container.Register<IDataStock>(typeof(DataStock));
var frmDisplayStock = container.Get<FrmDisplayStock>();
}
Nell'esempio sopra, l'ultima chiamata .Get
utilizzerà i tipi di cui è a conoscenza e il contenitore probabilmente presumerà quali tipi sono necessari per soddisfare l'intero grafico delle dipendenze, in modo identico a quanto è stato fatto nella nostra precedente esempio senza contenitore.
Quindi, in conclusione, vuoi andare nel punto più alto del tuo stack e lasciare che decida tutte le concrezioni. Non volete avere quei costruttori pubblici predefiniti che conoscono le concrezioni, perché ciò causa riferimenti strettamente accoppiati tra cose quando un'interfaccia sarebbe più che sufficiente. Non sai mai quando utilizzare un IDataStock
che funzioni su una cache ad alte prestazioni, su un webservice di terze parti o su un file locale, quindi non presumere che DataStock
sia l'unica implementazione che utilizzerai. Il punto chiave per prendere questa decisione al livello superiore è, se lo fai al di sotto di questo, troverai quel livello di dipendenze sopra quel punto e ora avrai come riferimento su lo stack per definirlo?
Le dipendenze devono essere un grafo diretto senza loop (DAG) e una singola radice (albero), in un albero non si lasciano mai che i peer si conoscano l'un l'altro, e non si fa mai conoscere ai figli i loro genitori. Quindi dove, ma alla radice, puoi fare riferimento a tutte le dipendenze senza infrangere le regole di un albero?
Un altro esempio più ampio che può rendere tutto più chiaro poiché il tuo esempio ha solo 2 dipendenze, non molto di un campione per illustrare un concetto.
public void Main()
{
var myWidgetsService = new WidgetService(
new WidgetEventsProcessor(
new MessageQueueSubscriber(ConfigurationManager.AppSettings["MQConnectionString"])
),
new WidgetInProcessCacheStore(),
new WidgetSerializerService(
new JsonSerializer()
),
new WidgetAccessControlService(
new AccessRightsProcessor(
new AccessRightsServiceClient(ConfigurationManager.AppSettings["AccessRightsServiceUri"])
),
new AuthenticationProcessor(
new WindowsAuthenticationChecker(ConfigurationManager.AppSettings["DomainController"]),
new EMailClient(ConfigurationManager.AppSettings["SMTPService"]) // for auth failure warnings
)
)
);
}
Dato l'albero delle dipendenze di cui sopra, devi solo effettuare le registrazioni e lasciare che il contenitore gestisca la costruzione (API IoC completamente creata, non una API di framework IoC reale o suggerita):
public void Main()
{
var container = new SomeIocContainer();
container.Register<IWindowsAuthenticationChecker>(typeof(WindowsAuthenticationChecker), ConfigurationManager.AppSettings["DomainController"]);
container.Register<IEMailClient>(typeof(EMailClient), ConfigurationManager.AppSettings["SMTPService"]);
container.Register<IAuthenticationProcessor>(typeof(AuthenticationProcessor));
container.Register<IAccessRightsServiceClient>(typeof(AccessRightsServiceClient), ConfigurationManager.AppSettings["AccessRightsServiceUri"]);
container.Register<IAccessRightsProcessor>(typeof(AccessRightsProcessor));
container.Register<IWidgetAccessControlService>(typeof(WidgetAccessControlService));
container.Register<IJsonSerializer>(typeof(JsonSerializer));
container.Register<IWidgetSerializerService>(typeof(WidgetSerializerService));
container.Register<IWidgetStore>(typeof(WidgetInProcessCacheStore));
container.Register<IWidgetSerializerService>(typeof(WidgetSerializerService));
container.Register<IMessageQueueSubscriber>(typeof(MessageQueueSubscriber), ConfigurationManager.AppSettings["MQConnectionString"]));
container.Register<IWidgetEventsProcessor>(typeof(WidgetEventsProcessor));
var myWidgetsService = container.Get<WidgetService>();
}