Programovanie

Ako používať inverziu riadenia v C #

Inverzia ovládania aj vkladanie závislostí vám umožňujú prerušiť závislosti medzi komponentmi vo vašej aplikácii a uľahčiť testovanie a údržbu vašej aplikácie. Inverzia riadenia a vkladanie závislostí však nie sú rovnaké - medzi nimi sú jemné rozdiely.

V tomto článku preskúmame inverziu riadiaceho vzoru a pochopíme, ako sa líši od vkladania závislostí pomocou relevantných príkladov kódu v jazyku C #.

Ak chcete pracovať s príkladmi kódu uvedenými v tomto článku, mali by ste mať vo svojom systéme nainštalovanú aplikáciu Visual Studio 2019. Ak ešte nemáte kópiu, môžete si tu stiahnuť Visual Studio 2019.

Vytvorte projekt konzolovej aplikácie v Visual Studio

Najprv si vytvoríme projekt konzolovej aplikácie .NET Core v Visual Studio. Za predpokladu, že je vo vašom systéme nainštalované Visual Studio 2019, vytvorte nový projekt konzolovej aplikácie .NET Core v Visual Studio podľa pokynov uvedených nižšie.

  1. Spustite Visual Studio IDE.
  2. Kliknite na „Vytvoriť nový projekt“.
  3. V okne „Vytvoriť nový projekt“ vyberte zo zobrazeného zoznamu šablón „Console App (.NET Core)“.
  4. Kliknite na Ďalej.
  5. V nasledujúcom okne „Konfigurácia nového projektu“ zadajte názov a umiestnenie nového projektu.
  6. Kliknite na tlačidlo Vytvoriť.

Týmto sa vytvorí nový projekt konzolovej aplikácie .NET Core v Visual Studio 2019. Tento projekt použijeme na preskúmanie inverzie kontroly v ďalších častiach tohto článku.

Čo je inverzia kontroly?

Inverzia riadenia (IoC) je návrhový vzor, ​​v ktorom je invertovaný riadiaci tok programu. Môžete využiť inverziu vzorov ovládacích prvkov na oddelenie komponentov vašej aplikácie, implementácie závislostí výmeny, simulované závislosti a urobiť vašu aplikáciu modulárnou a testovateľnou.

Vkladanie závislostí je podmnožinou princípu inverzie riadenia. Inými slovami, vkladanie závislostí je iba jedným zo spôsobov implementácie inverzie riadenia. Môžete tiež implementovať inverziu riadenia pomocou udalostí, delegátov, vzoru šablóny, továrenskej metódy alebo vyhľadávača služieb.

Inverzia vzoru návrhu ovládacieho prvku uvádza, že objekty by nemali vytvárať objekty, od ktorých závisia pri vykonávaní nejakej činnosti. Namiesto toho by mali dostať tieto objekty z vonkajšej služby alebo z kontajnera. Táto myšlienka je obdobou hollywoodskeho princípu, ktorý hovorí: „Nevolajte nám, zavoláme vám.“ Napríklad namiesto toho, aby aplikácia volala metódy v rámci, rámec by volal implementáciu, ktorá bola poskytnutá aplikáciou.

Inverzia príkladu kontroly v C #

Predpokladajme, že vytvárate aplikáciu na spracovanie objednávok a chcete implementovať protokolovanie. Z dôvodu zjednodušenia predpokladajme, že cieľ protokolu je textový súbor. Vyberte projekt konzolovej aplikácie, ktorý ste práve vytvorili v okne Solution Explorer, a vytvorte dva súbory s názvom ProductService.cs a FileLogger.cs.

  verejná trieda ProductService

    {

súkromné ​​iba na čítanie FileLogger _fileLogger = nový FileLogger ();

public void Log (reťazcová správa)

        {

_fileLogger.Log (správa);

        }

    }

verejná trieda FileLogger

    {

public void Log (reťazcová správa)

        {

Console.WriteLine („metóda Inside Log programu FileLogger.“);

LogToFile (správa);

        }

private void LogToFile (reťazcová správa)

        {

Console.WriteLine ("Metóda: LogToFile, Text: {0}", správa);

        }

    }

Implementácia uvedená v predchádzajúcom útržku kódu je správna, ale existuje určité obmedzenie. Máte obmedzenie na prihlásenie údajov iba do textového súboru. V žiadnom prípade nemôžete prihlásiť údaje do iných zdrojov údajov alebo do rôznych cieľov protokolu.

Nepružná implementácia ťažby dreva

Čo keby ste chceli prihlásiť údaje do databázovej tabuľky? Existujúca implementácia by to nepodporovala a vy by ste boli nútení implementáciu zmeniť. Môžete zmeniť implementáciu triedy FileLogger alebo môžete vytvoriť novú triedu, povedzme DatabaseLogger.

    verejná trieda DatabaseLogger

    {

public void Log (reťazcová správa)

        {

Console.WriteLine („metóda Inside Log programu DatabaseLogger.“);

LogToDatabase (správa);

        }

private void LogToDatabase (reťazcová správa)

        {

Console.WriteLine ("Metóda: LogToDatabase, Text: {0}", správa);

        }

    }

Môžete dokonca vytvoriť inštanciu triedy DatabaseLogger vo vnútri triedy ProductService, ako je uvedené v útržku kódu nižšie.

verejná trieda ProductService

    {

súkromné ​​iba na čítanie FileLogger _fileLogger = nový FileLogger ();

súkromné ​​iba na čítanie DatabaseLogger _databaseLogger =

new DatabaseLogger ();

public void LogToFile (reťazcová správa)

        {

_fileLogger.Log (správa);

        }

public void LogToDatabase (reťazcová správa)

        {

_fileLogger.Log (správa);

        }

    }

Aj keď by to fungovalo, čo keby ste potrebovali prihlásiť údaje svojej aplikácie do EventLogu? Váš návrh nie je flexibilný a budete nútení zmeniť triedu ProductService zakaždým, keď sa budete musieť prihlásiť do nového cieľa protokolu. To je nielen ťažkopádne, ale bude tiež pre vás nesmierne ťažké spravovať triedu ProductService v priebehu času.

Pridajte flexibilitu pomocou rozhrania

Riešením tohto problému je použitie rozhrania, ktoré by implementovali konkrétne triedy protokolovacích nástrojov. Nasledujúci úryvok kódu zobrazuje rozhranie s názvom ILogger. Toto rozhranie by implementovali dve konkrétne triedy FileLogger a DatabaseLogger.

verejné rozhranie ILogger

{

void Log (reťazcová správa);

}

Aktualizované verzie tried FileLogger a DatabaseLogger sú uvedené nižšie.

verejná trieda FileLogger: ILogger

    {

public void Log (reťazcová správa)

        {

Console.WriteLine („metóda Inside Log programu FileLogger.“);

LogToFile (správa);

        }

private void LogToFile (reťazcová správa)

        {

Console.WriteLine ("Metóda: LogToFile, Text: {0}", správa);

        }

    }

verejná trieda DatabaseLogger: ILogger

    {

public void Log (reťazcová správa)

        {

Console.WriteLine („metóda Inside Log programu DatabaseLogger.“);

LogToDatabase (správa);

        }

private void LogToDatabase (reťazcová správa)

        {

Console.WriteLine ("Metóda: LogToDatabase, Text: {0}", správa);

        }

    }

Teraz môžete kedykoľvek použiť alebo zmeniť konkrétnu implementáciu rozhrania ILogger. Nasledujúci úryvok kódu zobrazuje triedu ProductService s implementáciou metódy Log.

verejná trieda ProductService

    {

public void Log (reťazcová správa)

        {

ILogger logger = nový FileLogger ();

logger.Log (správa);

        }

    }

Zatiaľ je všetko dobré. Čo však v prípade, ak by ste chceli použiť DatabaseLogger namiesto FileLogger v metóde Log triedy ProductService? Implementáciu metódy Log v triede ProductService môžete zmeniť, aby ste splnili požiadavku, ale to neznamená, že je dizajn flexibilný. Poďme teraz urobiť návrh flexibilnejším pomocou inverzie riadenia a vkladania závislostí.

Invertujte ovládací prvok pomocou vloženia závislosti

Nasledujúci úryvok kódu ilustruje, ako môžete využiť injekciu závislostí na odovzdanie inštancie triedy konkrétneho protokolovacieho nástroja pomocou injekcie konštruktora.

verejná trieda ProductService

    {

súkromné ​​iba na čítanie ILogger _logger;

verejná služba ProductService (ILogger logger)

        {

_logger = logger;

        }

public void Log (reťazcová správa)

        {

_logger.Log (správa);

        }

    }

Na záver sa pozrime, ako môžeme odovzdať implementáciu rozhrania ILogger triede ProductService. Nasledujúci úryvok kódu ukazuje, ako môžete vytvoriť inštanciu triedy FileLogger a pomocou injekcie konštruktora odovzdať závislosť.

static void Main (reťazec [] args)

{

ILogger logger = nový FileLogger ();

ProductService productService = nový ProductService (logger);

productService.Log („Hello World!“);

}

Týmto sme prevrátili riadenie. Trieda ProductService už nie je zodpovedná za vytvorenie inštancie implementácie rozhrania ILogger alebo dokonca za rozhodnutie, ktorá implementácia rozhrania ILogger sa má použiť.

Inverzia kontroly a vloženie závislosti vám pomôžu s automatickým vytváraním inštancií a správou životného cyklu vašich objektov. ASP.NET Core obsahuje jednoduchú zabudovanú inverziu ovládacieho kontajnera s obmedzenou sadou funkcií. Tento vstavaný kontajner IoC môžete použiť, ak sú vaše potreby jednoduché, alebo môžete použiť kontajner tretej strany, ak chcete využiť ďalšie funkcie.

Viac o tom, ako pracovať s inverziou ovládania a vkladaním závislostí v ASP.NET Core, si môžete prečítať v mojom staršom príspevku tu.

$config[zx-auto] not found$config[zx-overlay] not found