Ta članek je zrcalni članek strojnega prevajanja, kliknite tukaj za skok na izvirni članek.

Pogled: 20516|Odgovoriti: 0

[Napitnine] Sedeminštirideset načinov za optimizacijo programa v C#

[Kopiraj povezavo]
Objavljeno na 15. 03. 2018 10:41:59 | | |

1. Zamenjajte dostopna polja z atributi

1、. .NET vezavo podatkov podpira le vezavo podatkov, prednosti vezave podatkov pa lahko pridobite z uporabo atributov.
2. Pri dostopu do lastnosti lahko uporabite zaklepanje za dodajanje podpore za večnitnost.

2. readonly (konstanta v času izvajanja) in const (konstanta časa prevajanja)

1. const se lahko uporablja le za primitivne tipe, enume in nize, medtem ko je readonly lahko katerikoli tip;
2. Const bo ob prevajanju zamenjan s specifično konstanto, tako da če se v referenci uporabita tako const kot readonly vrednosti, bo sprememba v readonly spremenila prvotni namen zasnove, to je potreba po ponovnem prevajanju spremenjenega sestava za ponovno referenco na novo konstantno vrednost.
3. Const je učinkovitejši od readonly, vendar izgubi prilagodljivost pri uporabi.

3. IS in AS

1. Oba sta pretvorba tipov med izvajanjem, saj se operatorji lahko uporabljajo le v referenčnih tipih, medtem ko lahko uporablja vrednosti in referenčne tipe;
2. Običajna praksa je, da se IS določi za določanje tipa, nato pa se selektivno izbere kot ali za močan operator pretvorbe tipov (pretvorba, ki jo določi operater).

4. Pogojni atribut namesto #if #endif条件编译

1. ConditionalAttribute se uporablja le na ravni metode, drugi elementi, kot so tipi, atributi itd., pa so neveljavni. In #if #endif则不受此限制;
2. ConditionalAttribute lahko doda več operacij OR (OR) za pogoje prevajanja, in #if #endif则可以添加与(AND) [tukaj je mogoče popolnoma definirati kot drug ločen simbol];
3. Definicijo CondioanlAttribute je mogoče postaviti v ločeno metodo, da je program bolj prilagodljiv.

5. Zagotovite metodo ToString()

1. Uporabnikom lahko zagotovi podrobnejše informacije na bolj prijazen način;
2. Uporabite metodo IFormatter.ToString() za bolj prilagodljivo prilagoditev, in če dodate vmesnika IFormatProvider in ICustomFormatter, bo bolj smiselno prilagoditi izhod sporočila.

6. Razlika med vrednostjo in vrsto reference

1. Tipi vrednosti ne podpirajo polimorfizma, ki je primeren za shranjevanje podatkov, ki jih upravljajo aplikacije, medtem ko reference podpirajo polimorfizem, ki je primeren za definiranje vedenja aplikacij.
2. Za tabele, definirane kot vrste vrednosti, se lahko zmogljivost programa bistveno izboljša;
3. Tip vrednosti ima manj fragmentacije pomnilnika v kupu, neuporabnosti pomnilnika in časa posrednega dostopa, njen vnos v metodi pa se izvaja v obliki replikacije, da se izogne izpostavitvi notranje strukture zunanjemu svetu.
4. Vrste vrednosti se uporabljajo v naslednjih scenarijih: Odgovornosti tipov se večinoma uporabljajo za shranjevanje podatkov; Javni vmesniki so popolnoma definirani z nekaterimi atributi dostopa podatkovnih članov; Podrazredov nikoli ni; Nikoli ni polimorfnega vedenja.

7. Vrednosti tipov je treba implementirati čim bolj konstantne in atomske tipe

1. Olajšati pisanje in vzdrževanje naše kode;
2. Tri strategije za inicializacijo konstant: pri konstrukciji; rastlinska metoda; Zgradite spremenljiv pomožni razred (npr. StringBuilder).

8. Zagotovite, da je 0 vredna veljavnega statusa

1. Privzeto stanje vrste vrednosti naj bo 0;
2. 0 enum tipa ne sme biti neveljavna; V FlagsAttribute zagotavlja, da je vrednost 0 veljavna v stanju;
3. Ko je niz prazen, se lahko vrne niz. prazni niz za prazno.

9. Večkratna reprezentacijska razmerja z enako presojo

1. ReferenceEquals() določa, da sta referenci enaki, in to mora veljati, kadar se obe nanašata na isti objekt.
2. Statična metoda Equals() se uporablja najprej za referenčno presojo, nato pa za oceno vrste vrednosti;
3. Za presojo vrste reference lahko uporabite metodo prepisovanja Equals() pri uporabi semantike vrednosti.
4. Pri prepisovanju metode Equals() je treba prepisati tudi metodo GetHashCode(), hkrati pa izvesti operacijo operator==().

10. Razumeti pomanjkljivosti metode GetHashCode()

1. GetHashCode() se uporablja le za zgoščene vrednosti zgoščenih ** definiranih ključev, kot sta HashTable ali Dictionary;
2. GetHashCode() naj sledi ustreznim trem pravilom: dva enaka objekta morata vrniti isto zgoščevalno kodo; naj bo invarianta za primer; Zgoščevalna funkcija naj proizvede naključno porazdelitev med vsemi celimi števili.

11. Dajte prednost uporabi foreach loop stavkov

1. foreach lahko odpravi preverjanje prevajalnika meje polja v zanki for (for);
2. Krožna spremenljivka foreach je samo za branje in obstaja eksplicitna transformacija, ki sproži izjemo, kadar je tip objekta ** napačen;
3. **, ki je potrebna za uporabo foreach, je: imeti javno metodo GetEnumberator(); IEnumerable vmesnik je eksplicitno implementiran. Implementiran je vmesnik IEnumeratorja;
4. foreach lahko prinese prednosti upravljanja virov, saj če prevajalnik določi IDisposable vmesnik, lahko uporabi optimiziran try... na koncu blokiraj;

12. Inicializacija privzetega polja je boljša kot izjava o dodelitvi

1. Življenjska doba polja bo privzeto inicializirala tip vrednosti na 0, referenčni tip pa na null.
2. Večkratna inicializacija istega objekta zmanjša učinkovitost izvajanja kode.
3. Namestitev inicializacije polja v konstruktor je primerna za obravnavo izjem.

13. Uporabite statični konstruktor za inicializacijo statičnih članov

1. Statični konstruktor se izvede pred dostopom do katere koli metode, spremenljivke ali atributa razreda;
2. Statična polja se prav tako izvajajo pred statičnim konstruktorjem, statični konstruktor pa je primeren za obravnavo izjem.

14. Uporabite verigo konstruktorjev (v. NET 4.0 ta problem že rešuje z opcijskimi parametri)

1. Uporabite to za predajo inicializacijskega dela drugemu konstruktorju in uporabite bazo za klic konstruktorja osnovnega razreda;
2. Zaporedje operacij primerkov tipov je: vsa statična polja nastavite na 0; Izvajanje statičnih inicializatorjev polja; statični konstruktor, ki izvaja osnovni razred; Statični konstruktorji, ki izvajajo trenutni tip;
Vsa polja instanc nastavite na 0; Izvajanje inicializatorjev polj instance; Izvedite ustreznega konstruktorja instance osnovnega razreda; Izvedite konstruktor instance trenutne vrste.

15. Uporaba stavkov using in try/finally za čiščenje virov

V metodi Dispose() na vmesniku IDisposable se GC.SuppressFinalize() lahko uporabi za obveščanje zbiralnika smeti, da končna operacija ni več izvedena.

16. Minimizirajte smeti v pomnilniku

1. Za dodelitev in uničenje predmetov na kupu je potreben dodatni procesorski čas;
2. Tehnike za zmanjšanje števila dodeljenih objektov: pogosto uporabljene lokalne spremenljivke se promovirajo v polja; Zagotavlja razred, ki shranjuje skupne primere Singleton objektov, ki izražajo določene tipe.
3. Uporabite StringBuilder za izvajanje kompleksnih nizovnih operacij.

17. Zmanjšajte pakiranje in razpakiranje

1. Pozorni na implicitno pretvorbo tipa v System.Object, in tip vrednosti ne sme biti zamenjan s tipom System.Object;
2. Uporaba vmesnikov namesto tipov lahko prepreči 'boxing', torej implementacijo vrednostnih tipov iz vmesnikov in nato klicanje članov preko vmesnikov.

18. Uvedba standardnega načina Odstranjevanja

1. Za uporabo nepomnilniških virov mora imeti finalizer, garbage collector doda implementirane finalizer objekte v terminacijsko vrsto po zaključku pomnilniških objektov, ki jih še niso zaključili, nato pa garbage collector začne novo nit za zagon finalizatorjev na teh objektih. S tem se lahko izognete težavam z uhajanjem pomnilnika, ki bi ga povzročila neizproščena neupravljana pomnilniška sredstva.
2. Uporaba metode IDisposable.dispose() zahteva štiri vidike dela: sprostitev vseh neupravljanih virov; Sprostite vse upravljane vire; Nastavite oznako statusa, ki označuje, ali je bil Dispose() izveden; Pokličite GC.SuppressFinalize(this), da prekličete operacijo zaključka objekta;
3. Dodajte zaščiteno virtualno metodo Dispose() tipu, ki potrebuje polimorfizem, in izpeljani razred sprosti svojo nalogo s prepisom te metode.
4. Pri tipu, ki zahteva IDizoposabilni vmesnik, bi morali implementirati terminator, tudi če ga ne potrebujemo.

19. Definirajte in implementirajte vmesnike nad tipi dedovanja

1. Nepovezani tipi lahko skupaj implementirajo skupni vmesnik, in lažje je implementirati vmesnik kot dedovanje;
2. Vmesnik je razmeroma stabilen, saj zajema nabor funkcij v vmesniku kot druge vrste implementacijskih kontraktov, medtem ko se osnovni razred lahko sčasoma razširi.

20. Razlikovati med implementacijo vmesnika in prepisovanjem virtualnih metod

1. Pri implementaciji vmesnika v osnovnem razredu mora izpeljani razred uporabiti new, da skrije uporabo metode osnovnega razreda;
2. Metoda osnovnega razrednega vmesnika se lahko deklarira kot virtualna metoda in nato implementira v izpeljanem razredu.

21. Uporaba zaupanja za izražanje povratnih klicev

1. Sam delegat ne zagotavlja zajemanja izjem, zato bo vsak večkanalni delegatski klic končal celotno verigo klicev.
2. Z prikazovanjem in klicanjem vsake ciljne delegacije v verigi delegatov lahko preprečite, da večkastni delegati vračajo le izhod zadnjega delegata.

22. Uporaba dogodkov za definiranje zunanjih vmesnikov

1. To naj bo deklariran kot skupni dogodek in naj prevajalnik ustvari metode dodajanja in premkljanja za nas.
2. Uporabite vsebnik System.ComponentModel.EventHandlerList za shranjevanje vsakega obravnavalnika dogodkov in ga uporabite za skrivanje kompleksnosti vseh dogodkov, kadar tip vsebuje veliko število dogodkov.

23. Izogibajte se vračanju referenc na notranje objekte razreda

1. Ker dostop do objekta tipa vrednosti ustvari kopijo objekta, atributi definiranja tipa vrednosti ne bodo spremenili stanja znotraj objekta tipa;
2. Vrste konstant lahko preprečijo spreminjanje stanja objekta;
3. Definirajte vmesnik tako, da omejite dostop do podmnožice in zmanjšate škodo na notranjem stanju objekta.
4. Definirajte objekt ovijalca za omejitev dostopa do drugega objekta;
5. Ko koda stranke spremeni notranje podatkovne elemente, se lahko implementira način Observer, tako da objekt lahko preveri ali ustreza spremembam.

24. Deklarativno programiranje je boljše od imperativnega programiranja

Možnost napak v več podobnih ročno napisanih algoritmih se lahko izogne, zato je zagotovljena jasna in berljiva koda.

25. Implementirajte tipe čim bolj serializirajoče

1. Tip ne predstavlja uporabniškega vmesnika, okna ali obrazca, in tip mora podpirati serijalizacijo;
2. Pri dodajanju deserializiranega atributa NonSerializedAttribute se privzeta vrednost lahko naloži z metodo OnDeserialization(), ki implementira IDeserializationCallback;
3. Pri nadzoru različic lahko uporabite vmesnik ISerializable za prilagodljiv nadzor in zagotovite konstruktor serializacije za inicializacijo objektov glede na podatke v toku, poleg tega pa potrebujete dovoljenje za izjeme SerializationFormatter pri implementaciji.
4. Če morate ustvariti izpeljani razred, morate za izpeljani razred zagotoviti metodo kljuke.

26. Uporaba vmesnikov IComparable in IComparer za implementacijo relacijov razvrščanja

1. IComparable vmesnik se uporablja za izvajanje najbolj naravnega razvrščanja za tipe, preobremenjuje štiri primerjalne operatorje in zagotavlja preobremenjeno različico metode CompareTo() za sprejemanje določenih tipov kot parametrov.
2. IComparer se uporablja za zagotavljanje sortirnih odnosov, ki se razlikujejo od IComparable, ali za zagotavljanje sortirnih odnosov, za katere tip sam trdi, da niso implementirani.

27. Izogibajte se ICloneable vmesnikom

1. Za vrste vrednosti ni potrebe po podpori ICloneable vmesnika, uporabite le privzeto operacijo dodeljevanja;
2. Za osnovne razrede, ki morda potrebujejo podporo ICloneable vmesnikov, je treba zanje ustvariti zaščiten replikacijski konstruktor, IConeable vmesnike pa je treba izogibati.

28. Izogibajte se prisilnim pretvorbam operaterjev

Uporaba konstruktorjev namesto operatorjev pretvorbe lahko naredi pretvorbo bolj jasne, kar lahko hitro povzroči nenavadne napake zaradi začasnih objektov, ki se uporabljajo po pretvorbi.

29. Razmislite o uporabi novega modifikatorja le, kadar kopičenje novih različic povzroča težave

30. Implementirati CLS-kompatibilne sestave čim bolj
1. Za ustvarjanje združljive sestave je treba upoštevati dve pravili: parametri in vrste povratnih vrednosti, ki jih uporabljajo vsi javni in zaščiteni člani skupščine, morajo biti združljivi s CLS; Vsak javni in zaščiten član, ki ni združljiv s CLS, mora imeti CLS-kompatibilno alternativo;
2. Preverjanje združljivosti CLS lahko zaobidete z eksplicitno implementacijo vmesnika, CLSCompliantAttribute pa ne bo preveril združljivosti zasebnih članov s CLS.

31. Čim bolj uvedite kratko in jedrnato metodo

1. JIT prevajalnik prevaja v enotah metod, in metode, ki niso klicane, JIT ne prevaja;
2. Če je koda stavka Case v daljšem Switchu zamenjana z eno metodo naenkrat, se čas, ki ga prihrani JIT prevajalnik, pomnoži;
3. Kratke in jedrnate metode ter izbira manj lokalnih spremenljivk lahko dosežejo optimalno uporabo registrov;
4. Manj kontrolnih vej v metodi, lažje je JIT prevajalniku vstaviti spremenljivke v registre.

32. Čim bolj uresničiti majhne velikosti in visoko kohezivne sestave

1. Vse javne razrede in skupne osnovne razrede postaviti v nekatere sestave, orodne razrede, ki zagotavljajo funkcije za javne razrede, združiti v isto sestavo, ustrezne javne vmesnike zapakirati v lastne sklope in na koncu obdelati razrede, ki so povsod na horizontalni poziciji v aplikaciji;
2. V načelu je treba ustvariti dve vrsti komponent: ena je majhna in združena sestava s specifično funkcijo, druga pa velika in široka sestava s skupnimi funkcijami.

33. Omejiti vidnost tipov

1. Uporaba vmesnikov za razkrivanje funkcij tipov nam lahko olajša ustvarjanje notranjih razredov brez omejevanja njihove razpoložljivosti zunaj asemblerja;
2. Manj kot je javnih vrst izpostavljenih zunanjemu svetu, več možnosti imate za prihodnjo širitev in uvedbo sprememb.

34. Ustvariti veliko-granularni spletni API

To zmanjša pogostost in obremenitev transakcij med računalniki, saj strežniku naloži velike operacije in natančne izvajanja.

35. Prepisovanje je boljše od procesov dogodkov

1. Če procesor dogodkov vrže izjemo, drugi procesorji v verigi dogodkov ne bodo klicani, vendar se to ne bo zgodilo pri prepisani virtualni metodi.
2. Prepisovanje je veliko učinkovitejše kot procesorji asociativnih dogodkov, ki morajo iterirati po celotnem seznamu zahtev, kar zahteva več časa procesorja.
3. Dogodke je mogoče odgovarjati med izvajanjem, z večjo prilagodljivostjo, in več odzivov je mogoče povezati z istim dogodkom.
4. Splošno pravilo je, da se obravnava izpeljani dogodek, pri čemer je metoda prepisovanja boljša.

36. Poštena uporaba. .NET diagnostika v času izvajanja

1. System.Diagnostics.Debug\Trace\EventLog zagotavlja vsa orodja, potrebna za dodajanje diagnostičnih informacij v izvajanje, aplikacija pa lahko zapiše v sistemski dnevnik dogodkov, ko EventLog zagotovi komponento;
2. Nazadnje, ne pišite svoje diagnostične knjižnice, .NET FCL že ima osnovno knjižnico, ki jo potrebujemo.

37. Uporaba standardnih konfiguracijskih mehanizmov

1、. Razred System.Windows.Application ogrodja .NET določa lastnosti, s katerimi lahko vzpostavimo skupno pot konfiguracije;
2. Application.LocalAppDataPath in Application.userDataPath bosta generirala imena poti lokalnega podatkovnega imenika in uporabniških podatkov;
3. Ne zapisujte podatkov v sistemske imenike ProgramFiles in Windows, te lokacije zahtevajo višja varnostna dovoljenja, ne pričakujte, da imajo uporabniki dovoljenja za pisanje.

38. Prilagodite in podpirajte vezavo podatkov

1. Dva objekta BindingMananger in CurrencyManager izvajata prenos podatkov med kontrolo in virom podatkov;
2. Prednosti vezave podatkov: uporaba vezave podatkov je veliko enostavnejša kot pisanje lastne kode; Uporabiti ga je treba za obsege, ki niso le besedilni podatkovni elementi – druge prikazovalne lastnosti je mogoče prav tako omejiti; Za vezave podatkov Windowos Forms možnost upravljanja več nadzornih sinhronizacij virov podatkov, povezanih s preverjanjem;
3. Ko objekt ne podpira zahtevanih atributov, lahko podprete vezavo podatkov tako, da blokirate trenutni objekt in nato dodate želeni objekt.

39. Uporabi. .NET validacija

1. V ASP.NET je pet kontrol za preverjanje veljavnosti, CustomValidator pa lahko uporabite za izpeljavo novega razreda in dodajanje lastnega avtentikatorja.
2. Validacija Windows zahteva pod-System.Windows.Forms.Control.Validating za pisanje obdelovalca dogodkov.

40. Izberite ustrezno ** glede na potrebe

1. Polje ima dve očitni pomanjkljivosti: ni ga mogoče dinamično spreminjati; Spreminjanje velikosti je časovno potratno;
2. ArrayList združuje značilnosti enodimenzionalnih polj in povezanih seznamov; Queue in Stack sta posebna polja, ki temeljijo na polju;
3. Ko je program bolj prilagodljiv za dodajanje in brisanje elementov, lahko ustvari bolj robustne tipe, in ko ustvarja razred, ki simulira **, mora zanj implementirati indekserje in IEnumerable vmesnike.

41. DataSet je boljši od prilagojene strukture

1. DataSeti imajo dve slabosti: interakcija med DataSeti z uporabo XML mehanizma serializacije in non-.NET kodo ni zelo dobra; DataSet je zelo vsestranski vsebnik;
2. Močni tipi podatkovnih nizov kršijo več oblikovalskih pravil, njihova razvojna učinkovitost pa je veliko višja kot pri bolj elegantnih načrtih, ki jih sami napišejo.

42. Uporaba značilnosti za poenostavitev refleksije

Z oblikovanjem in implementacijo razredov funkcij, ki razvijalce silijo v deklariranje dinamično uporabnih tipov, metod in atributov, lahko zmanjšate napake med izvajanjem aplikacije in izboljšate zadovoljstvo uporabnikov programske opreme.

43. Izogibajte se pretirani uporabi refleksov

1. Parametri in povratne vrednosti, ki jih uporabljajo člani Invoke, so System.Object, ki pretvarja tipe med izvajanjem, vendar je možnost težav postala bolj verjetna.
2. Vmesnik nam omogoča jasnejši in bolj vzdržljiv sistem, refleksija pa je zelo močan mehanizem pozne vezave. .NET okvir ga uporablja za implementacijo vezave podatkov za Windows kontrole in spletne kontrole.

44. Ustvarite posebne razrede izjem za aplikacijo

1. Edini razlog, zakaj so potrebni različni razredi izjem, je, da uporabnikom omogočijo enostavno uporabo različnih pristopov k različnim napakam pri pisanju procesorjev za ujetje;
2. Kadar so lahko različna vedenja popravila, moramo ustvariti različne razrede izjem, tako da zagotovimo vse konstruktorje, ki jih podpira osnovni razred izjeme, lahko ustvarimo popolnoma funkcionalen razred izjem za aplikacijo in uporabimo atribut InnerException za shranjevanje vseh informacij o napakah, ki jih generirajo nižje nivojske napake.

45. Dajte prednost nenavadnim varnostnim zagotovilom

1. Močno jamstvo izjem zagotavlja najboljše ravnovesje med okrevanjem po izjemi in poenostavljenim ravnanjem z izjemami, stanje programa pa ostane nespremenjeno, ko je operacija prekinjena zaradi izjeme.
2. Izvesti obrambno kopiranje podatkov, ki jih je treba spremeniti, spremeniti obrambno kopijo teh podatkov, operacija vmes lahko povzroči izjemo, začasna kopija in izvirni objekt se zamenjata;
3. Terminatorji, metode Dispose() in ciljne metode, vezane na delegate, naj zagotovijo, da v nobenem primeru ne zavržejo izjem.

46. Zmanjšati interoperabilnost

1. Obstajajo trije stroški interoperabilnosti: stroški naštevanja podatkov med upravljanimi in neupravljanimi kupi, stroški preklapljanja med upravljano in neupravljano kodo ter razvojno delo razvijalcev, ki se ukvarjajo s hibridnimi okolji;
2. Uporaba blittable-tipa v interoperabilnosti lahko učinkovito replicira med upravljanimi in neupravljanimi okolji, ne da bi bila pod vplivom notranje strukture objekta.
3. Uporabite funkcijo In/Out za zagotovitev najbolj primernih nepotrebnih večkratnih replikacij in izboljšate zmogljivost z razglasitvijo načina naštetja podatkov.
4. Uporaba COM Interop za najpreprostejšo implementacijo interoperabilnosti s COM komponentami, uporaba P/Invoke za klic Win32 API-ja ali uporaba stikala /CLR v C++ prevajalniku za mešanje upravljane in neupravljane kode;

47. Dajte prednost varnostnim kodam

1. Izogibajte se dostopu do neupravljanega pomnilnika, kolikor je mogoče, saj izolirana shramba ne more preprečiti dostopa upravljane kode in zaupanja vrednih uporabnikov.
2. Ko sestavljalniki tečejo na spletu, razmislite o uporabi izoliranega pomnilnika, in kadar določeni algoritmi zahtevajo višja varnostna dovoljenja, je treba te kode izolirati v ločenem sestavu.

48. Obvladovanje relevantnih orodij in virov

1. Uporaba NUnit za vzpostavitev samodejnih enotskih testov (integriranih v VS2010);
2. Orodje FXCop bo pridobilo IL kodo v asemblerju, jo analiziralo glede na heterogena pravila kodiranja in najboljše prakse ter na koncu prijavilo kršitev.
3. ILDasm je orodje za razstavljanje IL, ki nam lahko pomaga pridobiti vpogled v podrobnosti;
4. Shared Source CLI je izvorna koda implementacije, ki vsebuje jedro .NET ogrodja in prevajalnik C#.




Prejšnji:Service Fabric - koncept stanja storitve
Naslednji:.net/c# SynchronizationContext za podrobnosti
Disclaimer:
Vsa programska oprema, programski materiali ali članki, ki jih izdaja Code Farmer Network, so namenjeni zgolj učnim in raziskovalnim namenom; Zgornja vsebina ne sme biti uporabljena v komercialne ali nezakonite namene, sicer uporabniki nosijo vse posledice. Informacije na tej strani prihajajo z interneta, spori glede avtorskih pravic pa nimajo nobene zveze s to stranjo. Zgornjo vsebino morate popolnoma izbrisati z računalnika v 24 urah po prenosu. Če vam je program všeč, podprite pristno programsko opremo, kupite registracijo in pridobite boljše pristne storitve. Če pride do kakršne koli kršitve, nas prosimo kontaktirajte po elektronski pošti.

Mail To:help@itsvse.com