Diskuze: Správné použítí

C# .NET .NET (C# a Visual Basic) Správné použítí American English version English version

Aktivity (3)
Avatar
Luboš Hnědý:25. srpna 17:13

Ahoj, dělám si aplikace v .net mvc a mám jeden problém. Ve svém projektu mám následující kód:

public partial class LogService : ILogService
{
    private readonly DBContext _con = new DBContext();

    public void LogNew(Log log)
    {
        _con.Logs.Add(log);
        _con.SaveChanges();
    }
}

public partial interface ILogService
{
    void LogNew(Log log);
}

Tuto službu použiji v následujícím kódu:

    public class DBLogger
    {
        private static readonly ILogService _logService = new LogService();

        public override void Write(string name, string description,)
        {
            var log = new Log()
            {
                                Name = name,
                Description = description
            };
            _logService.LogNew(log);
        }
    }
}

Službu mám samozřejmě registrovanou. Následující třídu chci použít v jiné třídě. Nyní to funguje bez problémů, ale mám pocit, že tady nepoužívám DI že?A pokud bych to použil jak se má což znamená vytvořit následující kód:

private readonly ILogService _logService;

 public DBLogger(ILogService logService)
 {
     _logService = logService;
 }

Tady je problém, že nevím jak vytvořit objekt té třídy DBLogger. Samozřejmě můžu new DbLogger(new LogService). Předem všem strašně moc děkuji za pomoc. :)

Zkusil jsem: Hledal jsem různě na netu, ale nenašel jsem dopověď, který by se mi hodila.

Chci docílit: Toho abych nenapsal nesmysl.

 
Odpovědět 25. srpna 17:13
Avatar
vajkuba1234
Člen
Avatar
Odpovídá na Luboš Hnědý
vajkuba1234:25. srpna 22:50

Pouzitim new vytvoris zavislost. Proto bys to mel provest skrze kontruktor a spravu instanci ponechat na IOC/DI containeru.

Nahoru Odpovědět 25. srpna 22:50
No hope, no future, JUST WAR! For world peace Israel must be DESTROYED!
Avatar
Odpovídá na vajkuba1234
Luboš Hnědý:25. srpna 23:38

Moc ti děkuji za odpověď uže jsem se pál, že mi nikdo neodepíše. Promiň, ale nevím jak to přesně udělat. Chci potom totiž vytvořit z té třídy DBLogger instanci a mam tam jen jeden konstruktor. A nevím co dát za ten parametr právě...

 
Nahoru Odpovědět 25. srpna 23:38
Avatar
vajkuba1234
Člen
Avatar
Odpovídá na Luboš Hnědý
vajkuba1234:25. srpna 23:43

Koukni treba zde:

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.1
Nahoru Odpovědět 25. srpna 23:43
No hope, no future, JUST WAR! For world peace Israel must be DESTROYED!
Avatar
Odpovídá na vajkuba1234
Luboš Hnědý:26. srpna 0:01

Kouknul jsem a není mi to zcela jasné... Nemohl by jsi mi to prosím ukázat na tom mím příkladu?

 
Nahoru Odpovědět 26. srpna 0:01
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:27. srpna 8:46

Asp neznam, ale v php, kdyz neco pres konstruktor, tak kod asi vypada takto

<?php
class mojeTrida
private $prom;
function __construct()
    {
    $this->prom = new nejakyjinyObjekt();
    $this->prom->login();
    }
function __destruct()
    {
    $this->prom->logout();
    $this->prom = null; // nebo free mem
    }

Jinymi slovy, ty ten objekt vytvaris v casti var promenne. Coz se muze ukazat casem jako problem kvuli prehlednosti a mozna i jinak.
U win (delphi, mozna i v asp) tusim misto __construct se pouziva pro class 'mojeTrida' function se stejnym nazvem, 'mojeTrida'.
Destruktor je zase dobre pouzivat k uvolneni pameti prave pro takove pripady, kdy si tam dovnit class zanasis dalsi objekty. Vsude se pis, jak to dela automaticky (i php), ale obcas potrebujes pamet uvolnit driv. A kdyz takove objekty mas v construct, destruct, tak vis, ktere muzes uvolnit. Nemusis je hledat ve vsech funkcich.

 
Nahoru Odpovědět  -5 27. srpna 8:46
Avatar
Martin Petrovaj
Překladatel
Avatar
Odpovídá na Luboš Hnědý
Martin Petrovaj:27. srpna 10:08

DI sa dá jednoducho chápať tak, že objekt (v tvojom prípade napr. DbLogger) by si nemal sám vytvárať inštancie svojich závislostí (čiže by si v ňom nemal mať žiadne new LogService()), ale dostane ich "odniekiaľ" a sám sa nestará odkiaľ. To odniekiaľ je samozrejme nejaký DI/IoC kontajner alebo niečo podobné a ten sa už líši podľa použitého frameworku. Je to skrátka nejaký objekt alebo trieda, ktorá sa stará o to, aby ostatné objekty v tvojej aplikácii dostali už vytvorené a nakonfigurované závislosti tak, ako potrebujú.

V tvojom príklade by to pri použití constructor injection zjednodušene prebiehalo na spôsob: na nejakej vyššej úrovni v aplikácii vytvorím potrebný logger -> pridám / zaregistrujem ho do IoC kontajnera -> kontajner ním následne "nainštanciuje" objekty, ktoré majú na logger závislosť a požadujú ho cez konštruktor ako parameter. Konkrétna implementácia jednotlivých krokov bude najskôr využívať reflexiu a rozoberať ju tu by bolo na dlhšie.

Samozrejme, je dobrý zvyk závislosti predávať cez interface (čo vidím, že sa snažíš dodržiavať, super), možno ešte dodám, že cez DI by si mal posielať do LogService aj databázu (ak to ešte niekde nerobíš).

A na záver si dovolím zareagovať na príspevok p. Mlicha, aby náhodou nedošlo k nedorozumeniu - v C# sa deštruktory takmer vôbec nepoužívajú, ak potrebuješ pri zániku nejakého objektu uvoľniť tzv. unmanaged resources (napr. spojenia k otvoreným súborom a pod.), tak v tom objekte implementuješ rozhranie IDisposable. Určite vždy uprednostňuj deterministické uvoľnovanie zdrojov cez tento interface pred spoliehaním sa na garbage collector.

Nahoru Odpovědět 27. srpna 10:08
if (this.motto == "") { throw new NotImplementedException(); }
Avatar
vajkuba1234
Člen
Avatar
Odpovídá na Luboš Hnědý
vajkuba1234:27. srpna 13:01

Co konkretne ti neni jasne?

Ty nacpes do konstruktoru to co potrebujes a instanci nevytvaris rucne ty pomoci slovicka "new", ale nechas ji vytvorit tak jako v tom tutorialu.

Nahoru Odpovědět 27. srpna 13:01
No hope, no future, JUST WAR! For world peace Israel must be DESTROYED!
Avatar
vajkuba1234
Člen
Avatar
Odpovídá na Peter Mlich
vajkuba1234:27. srpna 13:03

Proc porad pletes to PHP do jinych sekci?

Nahoru Odpovědět  +4 27. srpna 13:03
No hope, no future, JUST WAR! For world peace Israel must be DESTROYED!
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:27. srpna 15:59

Jj, jak pise Martin Petrovaj, to je vlastne lepsi. Uvnitr bys zadne new delat nemel, pokud se nejedna o struktury pro ukladani dat.

$sql = new sqlPripojeni(...)
$trida = new mojeTrida($sql)

A uvnitr si pak ve tride priradis do promenne objekt z konstruktoru.

function __construct($sql)
    {
    $this->sql = $sql;
    }

vajkuba1234 - protoze je to tam podobne a lepe se mi to vysvetluje nez bych pul dne googloval, jak to prepsat do tohoto jazyka a jeste mozna s vice chybami.

 
Nahoru Odpovědět  -4 27. srpna 15:59
Avatar
Odpovídá na Martin Petrovaj
Luboš Hnědý:29. srpna 16:28

Děkuju všem za odpovědi. Nejvíce mi pomohla od Martin Petrovaj. Chtěl bych se ještě zeptat na to jak si mám posílat i tu DB. Opravdu to mám dělat? Někdy (přesně nevím kdy) jsem četl, že z DB by se měl vytvářet objekt při každé službě, takže to tak není ?

 
Nahoru Odpovědět 29. srpna 16:28
Avatar
Odpovídá na Martin Petrovaj
Luboš Hnědý:29. srpna 16:46

A ještě jedna otázka pokud mám ještě například třídu, která zapisuje log zprávy do souboru mám to taky dát do DI? Nebo jenom třídy co komunikují s db?

 
Nahoru Odpovědět 29. srpna 16:46
Avatar
Martin Petrovaj
Překladatel
Avatar
Odpovídá na Luboš Hnědý
Martin Petrovaj:29. srpna 18:39

1 Nikto ti nebráni vytvoriť si napr. jeden DB kontext napr. pre handlovanie používateľov aplikácie, iný pre veci okolo kategórii a produktov (ak vyvíjaš napr. nejaký eshop) a pod. Neviem ale či je dobrý nápad (a či to vôbec funguje) vytvárať viac rovnakých kontextov (inštancií tej istej triedy odvodenej od bázového DB kontextu, ktoré pristupujú k tým istým dátam a vykonávajú nad nimi CRUD). Aj keby sa to dalo, už len kvôli jednoduchšiemu životu a menej zbytočným problémom by som sa tomu vyhýbal.

Osobne to robievam tak (a viem, že sa to robí dosť často), že z každého druhu kontextu (ak máš na celú aplikáciu jeden, tak fajn) si vytvorím jednu inštanciu (štandardne per request, ale ak voči tomu nemáš odpor a praktické zábrany, teoreticky ti nič nebráni ani v úplnom singletone, aj keď to je téma a problém sám o sebe) a túto inštanciu cez DI dostane každý, kto má na ten kontext závislosť (dependency).

2 Čo sa týka triedy na logovanie správ do súboru, opäť to závisí hlavne od tvojich potrieb, návrhu a fungovania tvojej aplikácie (a takto je to v podstate so všetkým :-) ). Povedal by som ale, že jednoznačne lepší nápad je obdobne ako s databázou mať len jeden logger a ten (ideálne cez DI) poskytnúť všetkým objektom, ktoré ho na niečo potrebujú. Budeš mať jednoduchší život pri konfigurácii toho logovania, keďže ti bude stačiť spravovať to na jednom mieste a pri jednom loggeri by ti mali odpadnúť potenciálne problémy napr. so súčasným zápisom do súboru z viacerých loggerov. Aj keby s tým v jednovláknovej aplikácii bolo problémov menej, stále IMO skončíš s výkonovo efektívnejším riešením.

Akceptované řešení
+20 Zkušeností
+1 bodů
Řešení problému
Nahoru Odpovědět 29. srpna 18:39
if (this.motto == "") { throw new NotImplementedException(); }
Avatar
Odpovídá na Martin Petrovaj
Luboš Hnědý:29. srpna 19:03

Super moc ti děkuju. Fakt bezvadně vysvětleno. :)

 
Nahoru Odpovědět 29. srpna 19:03
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 14 zpráv z 14.