1. Înlocuirea câmpurilor accesibile cu atribute
1、. Legarea datelor .NET suportă doar legarea datelor și poți beneficia de legarea datelor folosind atribute. 2. În accesul get and set la proprietate, poți folosi lock pentru a adăuga suport multi-threading.
2. readonly (constantă de rulare) și const (constantă de compilare)
1. const poate fi folosit doar pentru tipuri primitive, enum-uri și șiruri, în timp ce readonly poate fi de orice tip; 2. const va fi înlocuit cu o constantă specifică la compilare, astfel încât, dacă atât valoarea const, cât și cea de citire sunt folosite în referință, trecerea la doar citire va schimba intenția originală a designului, care este necesitatea recompilarii asamblării modificate pentru a rereferenți noua valoare constantă. 3. Const este mai eficient decât citirea simplă, dar pierde flexibilitatea aplicării.
3. IS și AS
1. Ambele sunt conversii de tip la rulare, deoarece operatorii pot fi folosiți doar în tipuri de referință, în timp ce is poate folosi valori și tipuri de referință; 2. Practica obișnuită este să se folosească IS pentru a determina tipul, apoi să se aleagă să se folosească ca sau un operator puternic de conversie a tipului (conversia definită de un operator) selectiv.
4. ConditionalAttribute în loc de #if #endif条件编译
1. ConditionalAttribute este folosit doar la nivel de metodă, iar alte elemente precum tipurile, atributele etc. sunt invalide. Și #if #endif则不受此限制; 2. ConditionalAttribute poate adăuga mai multe operații OR (OR) pentru condiții de compilare, iar #if #endif则可以添加与(AND) [aici poate fi complet definit ca un alt simbol separat]; 3. Definiția ConditioanlAttribute poate fi plasată într-o metodă separată pentru a face programul mai flexibil.
5. Furnizarea metodei ToString()
1. Poate oferi informații detaliate utilizatorilor într-un mod mai prietenos; 2. Folosește metoda IFormatter.ToString() pentru a oferi o personalizare mai flexibilă, iar dacă adaugi interfețele IFormatProvider și ICustomFormatter, va avea mai mult sens să personalizezi ieșirea mesajului.
6. Diferența dintre valoare și tipul de referință
1. Tipurile de valori nu suportă polimorfismul, care este potrivit pentru stocarea datelor operate de aplicații, în timp ce referințele susțin polimorfismul, care este potrivit pentru definirea comportamentului aplicației. 2. Pentru tablouri definite ca tipuri de valoare, performanța programului poate fi semnificativ îmbunătățită; 3. Tipul de valoare are mai puțină fragmentare a memoriei heap, gunoi de memorie și timp de acces indirect, iar revenirea sa în metodă se face sub formă de replicare pentru a evita expunerea structurii interne lumii exterioare. 4. Tipurile de valori sunt folosite în următoarele scenarii: Responsabilitățile tipurilor sunt folosite în principal pentru stocarea datelor; Interfețele publice sunt complet definite de unele atribute de acces ale membrilor de date; Nu există niciodată subclase; Nu există niciodată un comportament polimorfic.
7. Tipurile de valori ar trebui implementate cât mai constante și tipuri atomice posibil
1. Să facem codul nostru mai ușor de scris și întreținut; 2. Trei strategii pentru inițializarea constantelor: în construcție; metoda plantelor; Construiește o clasă auxiliară mutabilă (de exemplu, StringBuilder).
8. Asigură-te că 0 merită un statut valabil
1. Starea implicită a tipului de valoare ar trebui să fie 0; 2. 0 din tipul enum nu ar trebui să fie invalid; În FlagsAttribute este pentru a se asigura că valoarea 0 este o stare validă; 3. Când șirul este gol, un șir poate fi returnat. Sfoară goală pentru gol.
9. Relații multiple de reprezentare cu judecată egală
1. ReferenceEquals() determină că referințele sunt egale și trebuie să fie adevărat atunci când ambele se referă la același obiect. 2. Metoda statică Egal() este folosită pentru a face mai întâi judecata de referință, apoi pentru a judeca tipul de valoare; 3. Pentru judecata tipului de referință, poți folosi metoda de rescriere Egal() atunci când folosești semantica valorilor. 4. La rescrierea metodei Equals(), metoda GetHashCode() trebuie de asemenea rescrisă, iar operația operater==() trebuie furnizată în același timp.
10. Înțelegerea neajunsurilor metodei GetHashCode()
1. GetHashCode() se aplică doar valorilor hash ale cheilor definite pe bază de hash, cum ar fi HashTable sau Dictionary; 2. GetHashCode() ar trebui să urmeze cele trei reguli corespunzătoare: două obiecte egale ar trebui să returneze același cod hash; ar trebui să fie o invariantă de instanță; Funcția hash ar trebui să producă o distribuție aleatorie între toți întregii.
11. Acordați prioritate utilizării instrucțiunilor buclă foreach
1. foreach poate elimina verificarea de către compilator a limitei tabloului buclei for; 2. Variabila circulară a foreach este doar citire, iar există o transformare explicită, care aruncă o excepție atunci când tipul obiectului ** este incorect; 3. Numărul ** necesar de folosit pentru foreach este: să existe metoda publică GetEnumberator(); Interfața IEnumberable este implementată explicit. Interfața IEnumerator este implementată; 4. foreach poate aduce beneficiile gestionării resurselor, deoarece dacă compilatorul poate determina interfața IDisposabilă, poate folosi optimizarea try... în final blochează;
12. Inițializarea câmpului implicit este mai bună decât instrucțiunea de atribuire
1. Durata de viață a câmpului va inițializa tipul de valoare la 0 și tipul de referință la null în mod implicit. 2. Inițializarea aceluiași obiect de mai multe ori va reduce eficiența execuției codului. 3. Introducerea inițializării câmpului în constructor este favorabilă pentru gestionarea excepțiilor.
13. Folosirea constructorului static pentru a inițializa membrii statici
1. Constructorul static va fi executat înainte ca orice metodă, variabilă sau atribut al unei clase să fie accesat; 2. Câmpurile statice vor rula de asemenea înaintea constructorului static, iar constructorul static este favorabil pentru gestionarea excepțiilor.
14. Folosirea lanțului constructor (în. NET 4.0 rezolvă deja această problemă cu parametri opționali)
1. Folosește acest lucru pentru a preda munca de inițializare altui constructor și folosește baza pentru a chema constructorul clasei de bază; 2. Secvența de operații a instanțelor de tip este: setează toate câmpurile statice la 0; Execuția inițializatoarelor statice de câmp; un constructor static care execută clasa de bază; Constructori statici care execută tipul curent; Setează toate câmpurile de instanță la 0; Execută inițializatoarele câmpurilor de instanță; Executați constructorul de instanță de clasă de bază corespunzător; Executați constructorul de instanță de tipul curent.
15. Folosirea instrucțiunilor using și try/finally pentru a curăța resursele
În metoda Dispose() a interfeței IDisposable, GC.SuppressFinalize() poate fi folosit pentru a notifica colectorul de gunoi că operația finală nu mai este efectuată.
16. Minimizarea deșeurilor de memorie
1. Este nevoie de timp suplimentar procesorului pentru a aloca și distruge obiecte pe un heap; 2. Tehnici pentru reducerea numărului de obiecte atribuite: variabilele locale frecvent folosite sunt promovate în câmpuri; Oferă o clasă care stochează instanțe comune de obiecte Singleton care exprimă tipuri specifice. 3. Folosirea StringBuilder pentru a efectua operații complexe de șiruri.
17. Minimizează împachetarea și despachetarea
1. Acordați atenție conversiei implicite a unui tip în System.Object, iar tipul de valoare nu trebuie înlocuit cu tipul System.Object; 2. Utilizarea interfețelor în loc de tip poate evita boxarea, adică implementarea tipurilor de valoare din interfețe și apoi apelarea membrilor prin interfețe.
18. Implementarea modului standard Dispose
1. Pentru a folosi resurse non-memorie, trebuie să aibă un finalizer, garbage collector-ul va adăuga obiectele finalizer implementate în coada de terminare după ce a finalizat obiectele de memorie care nu le-au terminat, iar apoi garbage collector-ul va începe un nou fir de discuție pentru a rula finalizerele pe aceste obiecte. Acest lucru poate evita problema scurgerii de memorie cauzată de eliberarea resurselor de memorie negestionate. 2. Utilizarea metodei IDisposable.Dispose() necesită patru aspecte ale muncii: eliberarea tuturor resurselor negestionate; Eliberează toate resursele gestionate; Setați un marker de stare pentru a indica dacă Dispose() a fost executat; Cheamă GC.SuppressFinalize(this) pentru a anula operația de terminare a obiectului; 3. Adaugă o metodă virtuală protejată Dispose() la tipul care necesită polimorfism, iar clasa derivată își eliberează sarcina prin rescrierea acestei metode. 4. În tipul care necesită o interfață IDisoposabilă, ar trebui să implementăm un terminator chiar dacă nu avem nevoie de unul.
19. Definirea și implementarea interfețelor peste tipurile de moștenire
1. Tipurile neînrudite pot implementa împreună o interfață comună, iar implementarea unei interfețe este mai ușoară decât moștenirea; 2. Interfața este relativ stabilă, ea încapsulează un set de funcții într-o interfață așa cum alte tipuri de contracte de implementare, în timp ce clasa de bază poate fi extinsă în timp.
20. Distingerea între implementarea interfeței și rescrierea metodelor virtuale
1. Când se implementează o interfață în clasa de bază, clasa derivată trebuie să folosească new pentru a ascunde utilizarea metodei clasei de bază; 2. Metoda interfeței clasei de bază poate fi declarată ca o metodă virtuală și apoi implementată în clasa derivată.
21. Folosirea încredințării pentru a exprima callback-urile
1. Delegatul în sine nu oferă nicio captură a excepțiilor, astfel încât orice apel multicast delegat va încheia întregul lanț de apeluri. 2. Prin afișarea și apelarea fiecărei țintă de delegare din lanțul de delegați, poți evita ca delegații multicast să returneze doar ieșirea ultimului delegat.
22. Folosirea evenimentelor pentru a defini interfețe externe
1. Ar trebui declarat ca un eveniment comun și să lase compilatorul să creeze metode add și renmove pentru noi. 2. Folosiți containerul System.ComponentModel.EventHandlerList pentru a stoca fiecare handler de evenimente și folosiți-l pentru a ascunde complexitatea tuturor evenimentelor atunci când tipul conține un număr mare de evenimente.
23. Evitați returnarea referințelor la obiectele interne ale clasei
1. Deoarece accesul la un obiect de tip valoare va crea o copie a obiectului, atributele definirii unui tip de valoare nu vor schimba deloc starea din interiorul obiectului de tip; 2. Tipurile constante pot evita schimbarea stării obiectului; 3. Definiți interfața pentru a limita accesul la un subset pentru a minimiza daunele aduse stării interne a obiectului. 4. Definirea unui obiect wrapper pentru a restricționa accesul la un alt obiect; 5. Când codul clientului modifică elementele interne de date, modul Observator poate fi implementat, astfel încât obiectul să poată verifica sau corespunde modificărilor.
24. Programarea declarativă este mai bună decât programarea imperativă
Posibilitatea de a face greșeli în mai mulți algoritmi similari scriși de mână poate fi evitată și se oferă cod clar și lizibil.
25. Tipurile de implementări cât mai serializabile posibil
1. Tipul nu reprezintă un control UI, fereastră sau formular, iar tipul ar trebui să suporte serializarea; 2. Când se adaugă atributul deserializat al NonSerializedAttribute, valoarea implicită poate fi încărcată prin metoda OnDeserialization() care implementează IDeserializationCallback; 3. În controlul versiunilor, poți folosi interfața ISerializable pentru control flexibil și poți oferi un constructor de serializare pentru a inițializa obiectele conform datelor din flux, necesitând de asemenea permisiunea excepțiilor SerializationFormatter la implementare. 4. Dacă trebuie să creezi o clasă derivată, trebuie să oferi o metodă de cârlig pentru clasa derivată.
26. Folosirea interfețelor IComparable și IComparer pentru a implementa relațiile de sortare
1. Interfața IComparable este folosită pentru a implementa cea mai naturală relație de sortare pentru tipuri, supraîncărcând patru operatori de comparație și oferind o versiune suprasolicitată a metodei CompareTo() pentru a accepta tipuri specifice ca parametri. 2. IComparer este folosit pentru a oferi relații de sortare diferite de IComparable sau pentru a ne oferi relații de sortare pe care tipul însuși spune că nu le implementează.
27. Evitarea interfețelor izolabile
1. Pentru tipurile de valori, nu este nevoie să se suporte interfața ICloneable, doar să se folosească operația implicită de atribuire; 2. Pentru clasele de bază care ar putea avea nevoie să suporte interfețe ICloneable, ar trebui creat un constructor de replicare protejat pentru acestea, iar interfețele IConeable ar trebui evitate.
28. Evitarea operatorilor de conversie forțată
Folosirea constructorilor în loc de operatori de conversie poate face munca de conversie mai clară, ceea ce poate duce ușor la bug-uri ciudate din cauza obiectelor temporare folosite după conversie.
29. Luați în considerare folosirea noului modificator doar atunci când acumularea de versiuni noi cauzează probleme
30. Implementarea asamblărilor compatibile CLS cât mai mult posibil 1. Pentru a crea o asamblare compatibilă, trebuie urmate două reguli: parametrii și tipurile de valori de returnare folosite de toți membrii publici și protejați ai asamblării trebuie să fie compatibile cu CLS; Orice membru public și protejat care nu este compatibil cu CLS trebuie să aibă o alternativă compatibilă CLS; 2. Poți ocoli verificarea tipului de compatibilitate CLS implementând explicit interfața, iar CLSCompliantAttribute nu va verifica compatibilitatea CLS a membrilor privați.
31. Implementați o metodă scurtă și concisă pe cât posibil
1. Compilatorul JIT compilează în unități de metode, iar metodele care nu sunt apelate nu vor fi compilate de JIT; 2. Dacă codul instrucțiunii Case din Switch-ul mai lung este înlocuit cu o metodă pe rând, timpul economisit de compilatorul JIT va fi înmulțit; 3. Metodele scurte și concise și selectarea unui număr mai mic de variabile locale pot obține o utilizare optimizată a registrelor; 4. Cu cât mai puține ramuri de control în metodă, cu atât este mai ușor pentru compilatorul JIT să introducă variabile în registre.
32. Realizați pe cât posibil ansamblurile de dimensiuni mici și coezive ridicate
1. Să pună toate clasele publice și clasele de bază comună în unele asamblări, să pună clasele de unelte care oferă funcții pentru clasele publice în aceeași asamblare, să împacheteze interfețele publice relevante în propriile lor asamblări și, în final, să proceseze clasele care se află pe toată poziția orizontală în aplicație; 2. În principiu, ar trebui create două tipuri de componente: unul este un ansamblu mic și agregat cu o funcție specifică, iar celălalt este un ansamblu mare și larg cu funcții comune.
33. Limitarea vizibilității tipurilor
1. Utilizarea interfețelor pentru a expune funcțiile tipurilor poate face mai ușoară crearea unor clase interne fără a limita disponibilitatea lor în afara asamblării; 2. Cu cât sunt mai puține tipuri publice expuse lumii exterioare, cu atât ai mai multe opțiuni pentru extinderea și implementarea schimbărilor viitoare.
34. Crearea unui Web API cu detalii mari și granulare
Aceasta minimizează frecvența și încărcarea tranzacțiilor între mașini, plasând operațiuni mari și execuții detaliate pe server.
35. Rescrierea este mai bună decât procesoarele de evenimente
1. Dacă un procesor de evenimente aruncă o excepție, alți procesori de pe lanțul de evenimente nu vor fi apelați, dar acest lucru nu se va întâmpla cu metoda virtuală rescrisă. 2. Rescrierea este mult mai eficientă decât procesoarele de evenimente asociative, care trebuie să itere pe întreaga listă de cereri, ceea ce consumă mai mult timp de CPU. 3. Evenimentele pot fi răspunse la timpul execuției, cu mai multă flexibilitate, iar răspunsurile multiple pot fi asociate cu același eveniment. 4. Regula comună este să gestionezi un eveniment derivat, iar metoda de rescriere este mai bună.
36. Utilizare echitabilă. Diagnosticarea la rulare .NET
1. System.Diagnostics.Debug\Trace\EventLog oferă toate instrumentele necesare pentru ca programul să adauge informații de diagnostic la runtime, iar aplicația poate scrie în jurnalul de evenimente al sistemului atunci când EventLog-ul furnizează ingredientul; 2. În final, nu scrie propria bibliotecă de diagnostic, .NET FCL are deja biblioteca de bază de care avem nevoie.
37. Utilizarea mecanismelor standard de configurare
1、. Clasa System.Windows.Application a framework-ului .NET definește proprietățile pentru a stabili o cale comună de configurare; 2. Application.LocalAppDataPath și Application.userDataPath vor genera numele de căi ale directorului local de date și ale datelor utilizatorului; 3. Nu scrie date în ProgramFiles și în directoarele de sistem Windows, aceste locații necesită permisiuni de securitate mai ridicate, nu te aștepta ca utilizatorii să aibă permisiuni de scriere.
38. Personalizare și suport pentru legarea datelor
1. Cele două obiecte ale BindingManager și CurrencyManager realizează transferul de date între control și sursa de date; 2. Avantajele legării datelor: folosirea legării datelor este mult mai simplă decât scrierea propriului cod; Ar trebui folosit pentru domenii care nu sunt elemente de text – alte proprietăți de afișare pot fi de asemenea limitate; Pentru legăturile de date Windowos Forms, capacitatea de a gestiona sincronizarea mai multor controale ale surselor de date legate de verificări; 3. Când obiectul nu suportă atributele necesare, poți suporta legarea datelor prin blocarea obiectului curent și apoi adăugarea obiectului dorit.
39. Folosește. Validarea .NET
1. Există cinci controale în ASP.NET pentru a verifica validitatea și poți folosi CustomValidator pentru a deriva o nouă clasă care să adaugă propriul autentificator. 2. Validarea Windows necesită un sub-System.Windows.Forms.Control.Validating pentru a scrie un manager de evenimente.
40. Alege ** potrivit nevoilor
1. Matricea are două defecte evidente: nu poate fi redimensionată dinamic; Redimensionarea este consumatoare de timp; 2. ArrayList combină caracteristicile array-urilor unidimensionale și listelor legate, Queue și Stack sunt tablouri speciale bazate pe Array; 3. Când programul este mai flexibil în a adăuga și elimina elemente, poate crea tipuri mai robuste, iar când creează o clasă care simulează **, ar trebui să implementeze indexatori și interfețe IEnumberable pentru aceasta.
41. DataSet este mai bun decât structura personalizată
1. Seturile de date au două dezavantaje: interacțiunea dintre seturile de date folosind mecanismul de serializare XML și codul non-.NET nu este foarte bună; DataSet este un container foarte versatil; 2. Tipurile puternice de DataSets încalcă mai multe reguli de design, iar eficiența lor de dezvoltare este mult mai mare decât cea a designurilor mai elegante scrise de ele însele.
42. Folosirea caracteristicilor pentru a simplifica reflexia
Prin proiectarea și implementarea unor clase de funcționalități care obligă dezvoltatorii să declare tipuri, metode și atribute utilizabile dinamic, poți reduce erorile de rulare ale aplicației și poți îmbunătăți satisfacția utilizatorilor de software.
43. Evită suprasolicitarea reflexelor
1. Parametrii și valorile de returnare folosite de membrii Invoke sunt System.Object, care convertește tipurile la rulare, dar posibilitatea unor probleme a devenit mai probabilă. 2. Interfața ne permite să obținem un sistem mai clar și mai ușor de întreținut, iar reflexia este un mecanism foarte puternic de legare târzie. .NET framework îl folosește pentru a implementa legarea datelor pentru controalele Windows și web.
44. Creează clase specifice de excepție pentru aplicație
1. Singurul motiv pentru care sunt necesare diferite clase de excepție este pentru a permite utilizatorilor să abordeze ușor diferite erori diferite atunci când scriu procesatoare catch; 2. Când pot exista comportamente diferite de reparare, ar trebui să creăm o varietate de clase de excepție diferite, furnizând toți constructorii suportați de clasa de bază a excepțiilor, putem crea o clasă de excepție complet funcțională pentru aplicație și putem folosi atributul InnerException pentru a salva toate informațiile de eroare generate de condițiile de eroare de nivel inferior.
45. Acordați prioritate garanțiilor de siguranță anormale
1. Garanția puternică a excepțiilor oferă cel mai bun echilibru între recuperarea după excepție și gestionarea simplificată a excepțiilor, iar starea programului rămâne neschimbată atunci când operațiunea este întreruptă din cauza excepției. 2. Să facă o copie defensivă a datelor ce urmează a fi modificate, să modifice copia defensivă a acestor date, operația din mijloc poate cauza o excepție, iar copia temporară și obiectul original vor fi schimbate; 3. Terminatorii, metodele Dispose() și metodele țintă legate de delegați ar trebui să se asigure că nu aruncă excepții sub nicio formă.
46. Minimizarea interoperabilității
1. Există trei costuri ale interoperabilității: costul enumerării datelor între heap-uri gestionate și neadministrate, costul comutării între cod gestionat și cod neadministrat și munca de dezvoltare a dezvoltatorilor care lucrează cu medii hibride; 2. Folosirea tipului blittable în interop poate replica eficient între medii gestionate și negestionate fără a fi afectată de structura internă a obiectului. 3. Folosiți funcția In/Out pentru a asigura cele mai adecvate replicări multiple inutile și îmbunătățiți performanța declarând modul în care sunt enumerate datele. 4. Folosirea interoperării COM pentru a implementa interoperabilitatea cu componentele COM în cel mai simplu mod, folosirea P/Invoke pentru a apela API-ul Win32 sau utilizarea comutatorului /CLR al compilatorului C++ pentru a combina cod gestionat și neadministrat;
47. Prioritizarea codurilor de siguranță
1. Evitați accesul la memorie negestionată cât de mult posibil, iar stocarea izolată nu poate împiedica accesul de la codul gestionat și utilizatorii de încredere. 2. Când asamblările rulează pe web, luați în considerare utilizarea stocării izolate, iar când anumite algoritmi necesită permisiuni de securitate mai ridicate, acele coduri ar trebui izolate într-un ansamblu separat.
48. Stăpânește uneltele și resursele relevante
1. Utilizarea NUnit pentru a stabili teste unitare automate (integrate în VS2010); 2. Instrumentul FXCop va obține codul IL în asamblare, îl va analiza în raport cu regulile eterogene de codare și cele mai bune practici și, în final, va raporta încălcarea. 3. ILDasm este un instrument de dezasamblare a IL care ne poate ajuta să obținem informații detaliate; 4. Shared Source CLI este un cod sursă de implementare care conține nucleul framework-ului .NET și compilatorul C#. |