Ten artykuł jest lustrzanym artykułem tłumaczenia maszynowego, kliknij tutaj, aby przejść do oryginalnego artykułu.

Widok: 20516|Odpowiedź: 0

[Napiwki] Czterdzieści siedem sposobów optymalizacji programu C#

[Skopiuj link]
Opublikowano 15.03.2018 10:41:59 | | |

1. Zastąpienie dostępnych pól atrybutami

1、. Binding danych .NET obsługuje tylko wiązanie danych, a korzyści z wiązania danych można uzyskać, korzystając z atrybutów.
2. W dostępie do właściwości można użyć blokady, aby dodać wsparcie dla wielowątkowania.

2. readonly (stała czasowa wykonywania) i const (stała czasu kompilacji)

1. const może być używany tylko dla typów prymitywnych, enumów i ciągów znaków, podczas gdy readonly może być dowolnym typem;
2. Const zostanie zastąpiony konkretną stałą podczas kompilacji, tak że jeśli w referencji zostaną użyte zarówno wartości const, jak i readonly, zmiana na readonly zmieni pierwotny cel projektu, czyli potrzebę rekompilacji zmienionego zespołu w celu odwołania się do nowej wartości stałej.
3. const jest bardziej efektywny niż tylko do odczytu, ale traci elastyczność aplikacji.

3. IS i AS

1. Oba są konwersjami typów w czasie działania, ponieważ operatory mogą być używane tylko w typach odniesień, podczas gdy is może używać wartości i typów odniesień;
2. Zwyczajowa praktyka polega na użyciu IS do określenia typu, a następnie wyborczym wyborze operatora konwersji typu lub silnego operatora (konwersji zdefiniowanej przez operatora).

4. Atrybut warunkowy zamiast #if #endif条件编译

1. ConditionalAttribute jest używany tylko na poziomie metody, a inne elementy, takie jak typy, atrybuty itp., są nieprawidłowe. I #if #endif则不受此限制;
2. ConditionalAttribute może dodawać wiele operacji OR (OR) dla warunków kompilacji, a #if #endif则可以添加与(AND) [tutaj można całkowicie zdefiniować jako inny osobny symbol];
3. Definicję ConditioanlAttribute można umieścić w osobnej metodzie, aby uczynić program bardziej elastycznym.

5. Dostarcz metodę ToString()

1. Może dostarczać użytkownikom szczegółowe informacje w bardziej przyjazny sposób;
2. Użyj metody IFormatter.ToString(), aby zapewnić bardziej elastyczne dostosowania, a jeśli dodasz interfejsy IFormatProvider i ICustomFormatter, bardziej sensowne będzie dostosowanie wyjścia komunikatów.

6. Różnica między wartością a typem odniesienia

1. Typy wartości nie obsługują polimorfizmu, który nadaje się do przechowywania danych obsługiwanych przez aplikacje, natomiast odwołania wspierają polimorfizm, który nadaje się do definiowania zachowania aplikacji.
2. Dla tablic definiowanych jako typy wartości wydajność programu może zostać znacząco poprawiona;
3. Typ wartości ma mniej fragmentacji pamięci sterty, śmieci pamięci i czasu pośredniego dostępu, a jego powrót w metodzie odbywa się w formie replikacji, aby uniknąć narażenia wewnętrznej struktury na świat zewnętrzny.
4. Typy wartości są wykorzystywane w następujących scenariuszach: Odpowiedzialności typów są głównie wykorzystywane do przechowywania danych; Interfejsy publiczne są całkowicie definiowane przez niektóre atrybuty dostępu członków danych; Nigdy nie ma podklas; Nigdy nie występuje zachowanie polimorficzne.

7. Typy wartości powinny być implementowane jak najbardziej stałe i atomowe

1. Ułatwić pisanie i utrzymanie kodu;
2. Trzy strategie inicjalizacji stałych: w konstrukcji; metoda roślinna; Skonstruuj zmienną klasę pomocniczą (np. StringBuilder).

8. Upewnij się, że 0 zasługuje na ważny status

1. Domyślny stan typu wartości powinien wynosić 0;
2. 0 typu enum nie powinno być nieważne; W FlagsAttribute ma zapewnić, że wartość 0 jest poprawnym stanem;
3. Gdy ciąg jest pusty, można go zwrócić. Pusty ciąg za pusty.

9. Relacje wielorakich reprezentacji o równym osądzie

1. ReferenceEquals() określa, że odwołania są równe, i musi to być prawda, gdy oba odnoszą się do tego samego obiektu.
2. Statyczna metoda Równa się() jest używana najpierw do oceny referencyjnej, a następnie do oceny typu wartości;
3. Do oceny typu odniesienia można użyć metody przepisywania Equals() przy użyciu semantyki wartości.
4. Podczas przepisywania metody Equals() należy również przepisać metodę GetHashCode(), a operację operator==() należy jednocześnie wykonać.

10. Zrozumienie wad metody GetHashCode()

1. GetHashCode() jest stosowany tylko do wartości skrótu kluczy opartych na hashu ** zdefiniowanych kluczy, takich jak HashTable czy Dictionary;
2. GetHashCode() powinien spełniać odpowiadające trzy reguły: dwa równe obiekty powinny zwracać ten sam kod skrótu; powinien być inwariantem instancyjnym; Funkcja skrótu powinna generować losowy rozkład pomiędzy wszystkimi liczbami całkowitymi.

11. Priorytetowo nadać użycie instrukcji pętli foreach

1. foreach może wyeliminować kontrolę kompilatora granicy tablicy pętli for;
2. Zmienna kołowa foreach jest tylko do odczytu, a istnieje jawna transformacja, która wyrzuca wyjątek, gdy typ obiektu ** jest nieprawidłowy;
3. ** wymagane do użycia foreach to: mieć publiczną metodę GetEnumberator(); Interfejs IEnumerable jest wyraźnie zaimplementowany. Implementowany jest interfejs IEnumeratora;
4. foreach może przynieść korzyści z zarządzania zasobami, ponieważ jeśli kompilator potrafi określić interfejs IDizposable, może użyć zoptymalizowanego try... na koniec blok;

12. Inicjalizacja pola domyślnego jest lepsza niż instrukcja przypisania

1. Żywotność pola inicjalizuje typ wartości do 0, a typ odniesienia do wartości na null domyślnie.
2. Wielokrotna inicjalizacja tego samego obiektu zmniejsza efektywność wykonania kodu.
3. Umieszczenie inicjalizacji pola w konstruktorze sprzyja obsłudze wyjątków.

13. Użyj statycznego konstruktora do inicjalizacji statycznych członków

1. Statyczny konstruktor zostanie wykonany przed uzyskaniem dostępu do jakiejkolwiek metody, zmiennej lub atrybutu klasy;
2. Pola statyczne również będą działać przed konstruktorem statycznym, a konstruktor statyczny sprzyja obsłudze wyjątków.

14. Użyj łańcucha konstruktorów (w. NET 4.0 już rozwiązuje ten problem dzięki opcjonalnym parametrom)

1. Użyj tego, aby przekazać pracę inicjalizacyjną innemu konstruktorowi, a bazę użyć do wywołania konstruktora klasy bazowej;
2. Sekwencja operacji instancji typów jest następująca: ustaw wszystkie pola statyczne na 0; Wykonywanie inicjalizatorów statycznego pola; statyczny konstruktor wykonujący klasę bazową; Statyczne konstruktory wykonujące aktualny typ;
Ustaw wszystkie pola instancji na 0; Inicjalizatory pól instancji wykonaj; Wykonaj odpowiedni konstruktor instancji klasy bazowej; Wykonaj konstruktor instancji aktualnego typu.

15. Używaj instrukcji using i try/finally do oczyszczania zasobów

W metodzie Dispose() interfejsu IDisposable GC.SuppressFinalize() może być użyte do powiadomienia garbage collectora, że ostatnia operacja nie jest już wykonywana.

16. Minimalizacja śmieci pamięci

1. Potrzeba dodatkowego czasu procesora na alokację i zniszczenie obiektów na stercie;
2. Techniki zmniejszania liczby przypisanych obiektów: często używane zmienne lokalne są promowane do pól; Zapewnia klasę, która przechowuje wspólne instancje obiektów Singleton wyrażających określone typy.
3. Używaj StringBuildera do wykonywania złożonych operacji na ciągu ciągów.

17. Minimalizacja pakowania i rozpakowywania

1. Zwracaj uwagę na niejawną konwersję typu na System.Object, a typ wartości nie powinien być zastępowany typem System.Object;
2. Używanie interfejsów zamiast typów pozwala uniknąć "boxingu", czyli implementacji typów wartości z interfejsów, a następnie wywoływania członków przez interfejsy.

18. Implementacja standardowego trybu Dyspose

1. Aby użyć zasobów niebędących pamięcią, musi mieć finalizer, garbage collector doda zaimplementowane obiekty finalizera do kolejki zakończenia po ukończeniu obiektów pamięci, które ich nie zakończyły, a następnie garbage collector rozpocznie nowy wątek, aby uruchomić finalizery na tych obiektach. Pozwala to uniknąć problemu wycieku pamięci spowodowanego nieuwalnianiem niezarządzanych zasobów pamięci.
2. Użycie metody IDisposable.Dispose() wymaga czterech aspektów pracy: zwolnienia wszystkich zasobów niezarządzanych; Uwolnić wszystkie zarządzane zasoby; Ustaw znacznik statusu, aby wskazać, czy Dispose() został wykonany; Wywołaj GC.SuppressFinalize(this), aby anulować operację zakończenia obiektu;
3. Dodać chronioną wirtualną metodę Dispose() do typu, który wymaga polimorfizmu, a klasa pochodna zwalnia swoje zadanie poprzez przepisanie tej metody.
4. W typie, który wymaga interfejsu IDizoposowalnego, powinniśmy zaimplementować terminator, nawet jeśli go nie potrzebujemy.

19. Zdefiniuj i zaimplementuj interfejsy nad typami dziedziczenia

1. Typy niepowiązane mogą wspólnie implementować wspólny interfejs, a implementacja interfejsu jest łatwiejsza niż dziedziczenie;
2. Interfejs jest stosunkowo stabilny, zawiera zestaw funkcji w interfejsie, podobnie jak inne typy kontraktów implementacyjnych, podczas gdy klasa bazowa może być rozszerzana w czasie.

20. Rozróżnienie między implementacją interfejsu a przepisywaniem metod wirtualnych

1. Podczas implementacji interfejsu w klasie bazowej, klasa pochodna musi użyć nowej, aby ukryć użycie metody klasy bazowej;
2. Metoda interfejsu klasy bazowej może być zadeklarowana jako metoda wirtualna, a następnie zaimplementowana w klasie pochodnej.

21. Użyj powierzenia do wyrażania powiązań zwrotnych

1. Sam delegat nie zapewnia żadnego przechwytywania wyjątków, więc każde wywołanie delegata wielocastowego zakończy cały łańcuch połączeń.
2. Wyświetlając i wywołując każdy cel delegacji w łańcuchu delegatów, można uniknąć zwracania przez delegatów multicast tylko wynik ostatniego delegata.

22. Używanie zdarzeń do definiowania zewnętrznych interfejsów

1. Powinno być zadeklarowane jako wspólne zdarzenie i pozwolić kompilatorowi tworzyć dla nas metody dodawania i przesuwania.
2. Użyj kontenera System.ComponentModel.EventHandlerList do przechowywania każdego handlera zdarzeń i użyj go do ukrycia złożoności wszystkich zdarzeń, gdy typ zawiera dużą liczbę zdarzeń.

23. Unikaj zwracania odniesień do wewnętrznych obiektów klas

1. Ponieważ dostęp do obiektu typu wartości tworzy kopię obiektu, atrybuty definiujące typ wartości nie zmienią stanu wewnątrz obiektu typu;
2. Typy stałe mogą uniknąć zmiany stanu obiektu;
3. Zdefiniuj interfejs ograniczający dostęp do podzbioru i minimalizując uszkodzenia stanu wewnętrznego obiektu.
4. Zdefiniuj obiekt otoczenia ograniczający dostęp do innego obiektu;
5. Gdy kod klienta zmienia wewnętrzne elementy danych, można zaimplementować tryb Obserwatora, aby obiekt mógł zweryfikować lub odpowiadać zmianom.

24. Programowanie deklaratywne jest lepsze niż programowanie imperatywne

Można uniknąć możliwości popełnienia błędów w wielu podobnych ręcznie pisanych algorytmach, a także zapewniony jest przejrzysty i czytelny kod.

25. Implementuj typy jak najbardziej serializowalne

1. Typ nie reprezentuje kontrolera UI, okna ani formularza, a typ powinien obsługiwać serializację;
2. Dodając atrybut zdeserializowany NonSerializedAttribute, domyślna wartość może być załadowana metodą OnDeserialization(), która implementuje IDeserializationCallback;
3. W kontroli wersji możesz użyć interfejsu ISerializable do elastycznej kontroli, zapewnić konstruktor serializacji do inicjalizacji obiektów zgodnie z danymi w strumieniu, a także wymagać zgody na wyjątki SerializationFormatter podczas implementacji.
4. Jeśli musisz stworzyć klasę pochodną, musisz podać metodę haka dla tej klasy.

26. Używaj interfejsów IComparable i IComparer do implementacji relacji sortowania

1. Interfejs IComparable służy do implementacji najbardziej naturalnej relacji sortowania typów, przeciążając cztery operatory porównania i zapewniając przeciążoną wersję metody CompareTo() do akceptowania konkretnych typów jako parametrów.
2. IComparer służy do dostarczania relacji sortowania różniących się od IComparable lub do przedstawienia relacji, które sam typ deklaruje jako nieimplementowane.

27. Unikaj interfejsów ICloneowalnych

1. Dla typów wartości nie ma potrzeby obsługi interfejsu ICloneable, wystarczy użyć domyślnej operacji przypisania;
2. Dla klas bazowych, które mogą wymagać obsługi interfejsów ICloneable, należy dla nich stworzyć konstruktor replikacji chronionej, a interfejsy IConeable powinny być unikane.

28. Unikaj operatorów przymusowych konwersji

Użycie konstruktorów zamiast operatorów konwersji może ułatwić proces konwersji, co łatwo prowadzi do dziwnych błędów spowodowanych tymczasowymi obiektami używanymi po konwersji.

29. Rozważ użycie nowego modyfikatora tylko wtedy, gdy nagromadzenie nowych wersji powoduje problemy

30. Implementować zespoły kompatybilne z CLS tak bardzo, jak to możliwe
1. Aby stworzyć kompatybilny asembler, należy przestrzegać dwóch reguł: parametry i typy wartości zwrotu używane przez wszystkich publicznych i chronionych członków asemblera muszą być kompatybilne z CLS; Każdy publiczny i chroniony członek, który nie jest kompatybilny z CLS, musi mieć alternatywę zgodną z CLS;
2. Możesz obejść test zgodności typu CLS, implementując interfejs jawnie, a CLSCompliantAttribute nie sprawdzi zgodności CLS członków prywatnych.

31. Wprowadź jak największą i zwięzłą metodę

1. Kompilator JIT kompiluje w jednostkach metod, a metody, które nie są wywoływane, nie będą kompilowane przez JIT;
2. Jeśli kod instrukcji Case w dłuższym Switchu zostanie zastąpiony jedną metodą naraz, czas zaoszczędzony przez kompilator JIT zostanie pomnożony;
3. Krótkie i zwięzłe metody oraz wybór mniejszej liczby zmiennych lokalnych pozwalają na optymalne wykorzystanie rejestrów;
4. Im mniej gałęzi sterowania w metodzie, tym łatwiej kompilator JIT umieszcza zmienne w rejestrach.

32. Realizować jak największe możliwości małych rozmiarów i bardzo spójnych zespołów

1. Umieścić wszystkie klasy publiczne i wspólne klasy bazowe w niektórych zespołach, umieścić klasy narzędzi zapewniające funkcje dla klas publicznych w tym samym asemblerze, zapakować odpowiednie interfejsy publiczne do własnych asembleri, a na końcu przetworzyć klasy znajdujące się na poziomej pozycji w aplikacji;
2. W zasadzie należy tworzyć dwa typy komponentów: jeden to mały i zagregowany zespół o określonej funkcji, a drugi to duży i szeroki zespół o wspólnych funkcjach.

33. Ograniczenie widoczności typów

1. Używanie interfejsów do udostępniania funkcji typów może ułatwić tworzenie klas wewnętrznych bez ograniczania ich dostępności poza asemblerem;
2. Im mniej publicznych typów jest wystawionych na świat zewnętrzny, tym więcej masz opcji na przyszłą ekspansję i zmiany wdrożeń.

34. Stwórz duże, szczegółowe API Web API

Minimalizuje to częstotliwość i obciążenie transakcji między maszynami, przenosząc na serwer duże operacje i precyzyjne wykonywania.

35. Przepisywanie jest lepsze niż procesory zdarzeń

1. Jeśli procesor zdarzeń wyrzuci wyjątek, inne procesory w łańcuchu zdarzeń nie zostaną wywołane, ale nie stanie się to z przekształconą metodą wirtualną.
2. Przepisywanie jest znacznie bardziej efektywne niż procesory zdarzeń asocjacyjnych, które muszą iterować całą listę żądań, co zajmuje więcej czasu CPU.
3. Zdarzenia mogą być rozpatrywane w czasie działania, z większą elastycznością, a wiele odpowiedzi może być powiązanych z tym samym zdarzeniem.
4. Powszechną zasadą jest radzenie sobie z zdarzeniem pochodnym, a metoda przepisywania jest lepsza.

36. Dozwolony użytek. Diagnostyka w czasie działania .NET

1. System.Diagnostics.Debug\Trace\EventLog dostarcza wszystkie narzędzia potrzebne programowi do dodawania informacji diagnostycznych do czasu działania, a aplikacja może zapisywać do systemowego dziennika zdarzeń, gdy EventLog dostarcza składnik;
2. Na koniec, nie pisz własnej biblioteki diagnostycznej, .NET FCL już ma potrzebną nam bibliotekę podstawową.

37. Stosowanie standardowych mechanizmów konfiguracji

1、. Klasa System.Windows.Application w frameworku .NET definiuje właściwości, które pozwalają nam ustanowić wspólną ścieżkę konfiguracji;
2. Application.LocalAppDataPath i Application.userDataPath wygenerują nazwy ścieżek lokalnego katalogu danych i danych użytkownika;
3. Nie zapisuj danych w katalogach systemowych ProgramFiles i Windows, te miejsca wymagają wyższych uprawnień, nie oczekuj, że użytkownicy będą mieli uprawnienia do zapisu.

38. Dostosowanie i wsparcie wiązania danych

1. Dwa obiekty BindingMananger i CurrencyManager realizują transfer danych między kontrolą a źródłem danych;
2. Zalety wiązania danych: używanie wiązania danych jest znacznie prostsze niż pisanie własnego kodu; Powinien być używany dla zakresów innych niż dane tekstowe – inne właściwości wyświetlania również mogą być ograniczone; W przypadku wiązań danych Windowos Forms możliwość obsługi wielu kontrolnych źródeł danych związanych z kontrolą;
3. Gdy obiekt nie obsługuje wymaganych atrybutów, można wspierać wiązanie danych, blokując aktualny obiekt i dodając pożądany obiekt.

39. Użycie. Walidacja .NET

1. W ASP.NET jest pięć kontrolek do weryfikacji ważności, a CustomValidator można użyć CustomValidatora do wytworzenia nowej klasy i dodania własnego uwierzytelniacza.
2. Weryfikacja Windows wymaga podsystemu.Windows.Forms.Control.Validating do napisania obsługi zdarzeń.

40. Wybierz odpowiednie ** zgodnie z potrzebami

1. Tablica ma dwie oczywiste wady: nie można jej dynamicznie zmieniać rozmiaru; Zmiana rozmiaru jest czasochłonna;
2. ArrayList łączy cechy jednowymiarowych tablic i list powiązanych, Queue i Stack to specjalne tablice oparte na Array;
3. Gdy program jest bardziej elastyczny w dodawaniu i usuwaniu elementów, może tworzyć bardziej odporne typy, a przy tworzeniu klasy symulującej ** powinien zaimplementować indeksery i interfejsy IEnumerowalne.

41. DataSet jest lepszy niż niestandardowa struktura

1. DataSety mają dwie wady: interakcja między DataSetami wykorzystującymi mechanizm serializacji XML a kodem non-.NET nie jest zbyt dobra; DataSet to bardzo wszechstronny kontener;
2. Silne typy zbiorów danych łamią więcej zasad projektowania, a ich efektywność rozwoju jest znacznie wyższa niż w przypadku bardziej eleganckich projektów napisanych samodzielnie.

42. Wykorzystanie charakterystyk do uproszczenia refleksji

Projektując i implementując klasy funkcji, które zmuszają programistów do deklarowania dynamicznie użytecznych typów, metod i atrybutów, można zmniejszyć błędy w czasie działania aplikacji i zwiększyć satysfakcję użytkowników oprogramowania.

43. Unikaj nadmiernego używania odruchu

1. Parametry i wartości zwrotne używane przez członków Invoke to System.Object, który konwertuje typy w czasie działania, ale ryzyko problemów stało się bardziej prawdopodobne.
2. Interfejs pozwala nam uzyskać jaśniejszy i bardziej zrównoważony system, a refleksja jest bardzo potężnym mechanizmem późnego wiązania. Framework .NET wykorzystuje go do implementacji wiązania danych dla kontrolerów Windows i kontrolek webowych.

44. Stwórz konkretne klasy wyjątków dla aplikacji

1. Jedynym powodem, dla którego potrzebne są różne klasy wyjątków, jest umożliwienie użytkownikom łatwego podejścia do różnych błędów podczas zapisu procesorów catch;
2. Gdy mogą występować różne zachowania naprawcze, powinniśmy stworzyć różnorodne klasy wyjątków, dostarczając wszystkie konstruktory wspierane przez klasę bazową wyjątków, możemy stworzyć w pełni funkcjonalną klasę wyjątków dla aplikacji i użyć atrybutu InnerException do zapisania wszystkich informacji o błędzie generowanych przez niższego poziomu błędów.

45. Priorytetowo nadać gwarancjom bezpieczeństwa o nieprawidłowościach

1. Silna gwarancja wyjątków zapewnia najlepszą równowagę między odzyskiwaniem po wyjątku a uproszczonym obsługą wyjątków, a stan programu pozostaje niezmieniony po przerwaniu operacji z powodu wyjątku.
2. Wykonanie defensywnego kopiowania danych do modyfikacji, modyfikacja kopii obronnej tych danych, operacja pośrednia może spowodować wyjątek, a tymczasowa kopia i oryginalny obiekt zostaną wymienione;
3. Terminatory, metody Dispose() oraz metody docelowe powiązane z delegatami powinny zapewnić, że nie rzucają wyjątków w żadnych okolicznościach.

46. Minimalizacja interoperacyjności

1. Interoperacyjność wiąże się z trzema kosztami: kosztem wyliczania danych między zarządzanymi a niezarządzanymi stertami, kosztem przełączania się między kodem zarządzanym a niezarządzanym oraz pracą deweloperską pracującą w środowiskach hybrydowych;
2. Użycie typu blittable w interopie pozwala skutecznie replikować środowiska zarządzane i niezarządzane, bez wpływu na wewnętrzną strukturę obiektu.
3. Korzystaj z funkcji In/Out, aby zapewnić najbardziej odpowiednie, niepotrzebne wielokrotne replikacje oraz poprawić wydajność poprzez deklarowanie sposobu wyliczania danych.
4. Użyj interoperacyjnego COM do najprostszej implementacji interoperacyjności z komponentami COM, użyj P/Invoke do wywołania API Win32 lub przełącznika /CLR w kompilatorze C++ do mieszania kodu zarządzanego i niezarządzanego;

47. Priorytet nadać kodom bezpieczeństwa

1. Unikaj dostępu do pamięci niezarządzanej tak bardzo, jak to możliwe, ponieważ izolowana pamięć nie uniemożliwia dostępu kodu zarządzanego i zaufanych użytkowników.
2. Gdy asemblery działają w sieci, rozważ użycie izolowanej pamięci masowej, a gdy niektóre algorytmy wymagają wyższych uprawnień, te kody powinny być izolowane w osobnym asemblerze.

48. Opanowanie odpowiednich narzędzi i zasobów

1. Użycie NUnit do ustanawiania automatycznych testów jednostkowych (zintegrowanych z VS2010);
2. Narzędzie FXCop pozyska kod IL w asamblerze, przeanalizuje go względem heterogenicznych zasad kodowania i najlepszych praktyk, a następnie zgłosi naruszenie.
3. ILDasm to narzędzie do deskładowania IL, które pomaga nam zgłębiać szczegóły;
4. Shared Source CLI to kod źródłowy implementacji zawierający jądro frameworka .NET oraz kompilator C#.




Poprzedni:Service Fabric – koncepcja usługi stanowej
Następny:.net/c# SynchronizationContext dla szczegółów
Zrzeczenie się:
Całe oprogramowanie, materiały programistyczne lub artykuły publikowane przez Code Farmer Network służą wyłącznie celom edukacyjnym i badawczym; Powyższe treści nie mogą być wykorzystywane do celów komercyjnych ani nielegalnych, w przeciwnym razie użytkownicy ponoszą wszelkie konsekwencje. Informacje na tej stronie pochodzą z Internetu, a spory dotyczące praw autorskich nie mają z nią nic wspólnego. Musisz całkowicie usunąć powyższą zawartość z komputera w ciągu 24 godzin od pobrania. Jeśli spodoba Ci się program, wspieraj oryginalne oprogramowanie, kup rejestrację i korzystaj z lepszych, autentycznych usług. W przypadku naruszenia praw prosimy o kontakt mailowy.

Mail To:help@itsvse.com