1. Vervang toegankelijke velden door attributen
1、. .NET data binding ondersteunt alleen data binding, en je kunt de voordelen van data binding krijgen door attributen te gebruiken. 2. In de toegang tot de eigenschap kunt u lock gebruiken om ondersteuning voor multithreading toe te voegen.
2. alleen-lezen (runtimeconstante) en const (compileertijdconstante)
1. const kan alleen worden gebruikt voor primitieve types, enums en strings, terwijl readonly elk type kan zijn; 2. const wordt bij compileren vervangen door een specifieke constante, zodat als zowel const- als readonly-waarden in de referentie worden gebruikt, de wijziging naar alleen-lezen de oorspronkelijke bedoeling van het ontwerp zal veranderen, namelijk de noodzaak om de gewijzigde assembly opnieuw te compileren om de nieuwe constante waarde opnieuw te refereren. 3. Const is efficiënter dan alleen-lezen, maar verliest de flexibiliteit van toepassing.
3. IS en AS
1. Beide zijn typeconversies tijdens runtime, aangezien operatoren alleen in referentietypen gebruikt kunnen worden, terwijl het waarden en referentietypen kan gebruiken; 2. De gebruikelijke praktijk is om IS te gebruiken om het type te bepalen, en vervolgens selectief te kiezen om als of een sterke typeconversie-operator (conversie gedefinieerd door een operator) te gebruiken.
4. ConditionalAttribute in plaats van #if #endif条件编译
1. ConditionalAttribuut wordt alleen op methodeniveau gebruikt, en andere items zoals types, attributen, enz. zijn ongeldig. En #if #endif则不受此限制; 2. ConditionalAttribuut kan meerdere OR (OR)-operaties toevoegen voor compilatievoorwaarden, en #if #endif则可以添加与(EN) [hier kan volledig worden gedefinieerd als een ander apart symbool]; 3. De definitie van ConditioanlAttribute kan in een aparte methode worden geplaatst om het programma flexibeler te maken.
5. Geef de ToString()-methode
1. Het kan gedetailleerde informatie aan gebruikers op een vriendelijkere manier bieden; 2. Gebruik de IFormatter.ToString()-methode om flexibelere aanpassing te bieden, en als je de IFormatProvider- en ICustomFormatter-interfaces toevoegt, is het logischer om de berichtoutput aan te passen.
6. Het verschil tussen waarde en referentietype
1. Waardetypes ondersteunen geen polymorfisme, wat geschikt is voor het opslaan van gegevens die door applicaties worden beheerd, terwijl referenties polymorfisme ondersteunen, wat geschikt is voor het definiëren van applicatiegedrag. 2. Voor arrays die als waardetypes zijn gedefinieerd, kan de prestaties van het programma aanzienlijk worden verbeterd; 3. Het waardetype heeft minder heapgeheugenfragmentatie, geheugenafval en indirecte toegangstijd, en de terugkeer in de methode gebeurt in de vorm van replicatie om te voorkomen dat de interne structuur aan de buitenwereld wordt blootgesteld. 4. Waardetypes worden gebruikt in de volgende scenario's: De verantwoordelijkheden van types worden voornamelijk gebruikt voor gegevensopslag; Publieke interfaces worden volledig gedefinieerd door sommige attributen voor de toegang van dataleden; Er zijn nooit subklassen; Er is nooit polymorf gedrag.
7. Waardetypes moeten zo constant en atomair mogelijk worden geïmplementeerd
1. Onze code makkelijker te schrijven en te onderhouden maken; 2. Drie strategieën voor het initialiseren van constanten: in de constructie; plantmethode; Bouw een veranderlijke helperklasse (bijv. StringBuilder).
8. Zorg ervoor dat 0 een geldige status waard is
1. De standaardtoestand van het waardetype moet 0 zijn; 2. De 0 van het enumtype mag niet ongeldig zijn; In het FlagsAttribuut wordt ervoor gezorgd dat de waarde 0 een geldige toestand heeft; 3. Wanneer de string leeg is, kan een string worden teruggegeven. Lege string voor leeg.
9. Meervoudige representatieverhoudingen van gelijk oordeel
1. ReferenceEquals() bepaalt dat de referenties gelijk zijn, en het moet waar zijn wanneer beide naar hetzelfde object verwijzen. 2. De statische Equals()-methode wordt gebruikt om eerst een referentieoordeel te maken en vervolgens het waardetype te beoordelen; 3. Voor het beoordelen van het referentietype kun je de herschrijfmethode Equals() gebruiken bij het gebruik van waardesemantiek. 4. Bij het herschrijven van de Equals()-methode moet ook de GetHashCode()-methode worden herschreven en moet de operator==()-operatie tegelijkertijd worden uitgevoerd.
10. Begrijp de tekortkomingen van de GetHashCode()-methode
1. GetHashCode() wordt alleen toegepast op hashwaarden van hash-gebaseerde ** gedefinieerde sleutels, zoals HashTable of Dictionary; 2. GetHashCode() moet de bijbehorende drie regels volgen: twee gelijke objecten moeten dezelfde hashcode teruggeven; moet een instantie-invariant zijn; De hashfunctie zou een willekeurige verdeling over alle gehele getallen moeten produceren.
11. Geef prioriteit aan het gebruik van foreach-lus-statements
1. Foreach kan de controle van de compiler op de arraygrens van de for-lus elimineren; 2. De cirkelvormige variabele van foreach is alleen-lezen, en er is een expliciete transformatie die een uitzondering geeft wanneer het objecttype van het **-object onjuist is; 3. De ** die vereist is om voor elke te gebruiken is: gebruik de publieke GetEnumberator()-methode; De IEnumberable-interface is expliciet geïmplementeerd. De IEnumerator-interface is geïmplementeerd; 4. foreach kan de voordelen van resource management bieden, want als de compiler de IDisposable-interface kan bepalen, kan hij de geoptimaliseerde try... Tot slot blokken;
12. De initialisatie van het standaardveld is beter dan de toewijzingsinstructie
1. De veldlevensduur initialiseert standaard het waardetype naar 0 en het referentietype naar nul. 2. Het meerdere keren initialiseren van hetzelfde object vermindert de uitvoeringsefficiëntie van de code. 3. Het plaatsen van de initialisatie van het veld in de constructor bevordert de afhandeling van uitzonderingen.
13. Gebruik de statische constructor om statische leden te initialiseren
1. De statische constructor wordt uitgevoerd voordat een methode, variabele of attribuut van een klasse wordt geraadpleegd; 2. Statische velden zullen ook vóór de statische constructor draaien, en de statische constructor is bevorderlijk voor het behandelen van uitzonderingen.
14. Gebruik de constructor-keten (in. NET 4.0 lost dit probleem al op met optionele parameters)
1. Gebruik dit om het initialisatiewerk over te dragen aan een andere constructor, en gebruik base om de constructor van de basisklasse aan te roepen; 2. De bewerkingsvolgorde van type-instanties is: stel alle statische velden op 0; Uitvoering van statische veldinitialisatoren; een statische constructor die de basisklasse uitvoert; Statische constructors die het huidige type uitvoeren; Stel alle instantievelden in op 0; Uitvoer instantieveldinitialisatoren; Voer de juiste basisklasse instance constructor uit; Voer de instance constructor van het huidige type uit.
15. Gebruik using en try/finally statements om bronnen op te schonen
In de Dispose()-methode van de IDisposable-interface kan GC.SuppressFinalize() worden gebruikt om de garbage collector te informeren dat de laatste bewerking niet langer wordt uitgevoerd.
16. Minimaliseer geheugenrommel
1. Het kost extra processortijd om objecten op een heap toe te wijzen en te vernietigen; 2. Technieken om het aantal toegewezen objecten te verminderen: vaak gebruikte lokale variabelen worden gepromoveerd tot velden; Biedt een klasse die veelvoorkomende instanties van Singleton-objecten opslaat die specifieke types uitdrukken. 3. Gebruik StringBuilder om complexe stringbewerkingen uit te voeren.
17. Minimaliseer in- en uitpakken
1. Let op de impliciete conversie van een type naar System.Object, en het waardetype mag niet worden vervangen door het type. System.Object; 2. Het gebruik van interfaces in plaats van types kan boxing vermijden, dat wil zeggen het implementeren van waardetypes uit interfaces en vervolgens leden via interfaces oproepen.
18. Implementeer de standaard Dispose-modus
1. Om niet-geheugenresources te gebruiken, moet er een finalizer zijn; de garbage collector voegt de geïmplementeerde finalizer-objecten toe aan de terminatiewachtrij nadat de geheugenobjecten die ze niet hebben beëindigd zijn voltooid, en vervolgens start de garbage collector een nieuwe thread om de finalizers op deze objecten uit te voeren. Dit kan het probleem van geheugenlekken door het niet vrijgeven van onbeheerde geheugenbronnen vermijden. 2. Het gebruik van de IDisposable.Dispose()-methode vereist vier aspecten van werk: het vrijgeven van alle niet-beheerde bronnen; Maak alle beheerde middelen vrij; Stel een statusmarker in om aan te geven of Dispose() is uitgevoerd; Roep GC.SuppressFinalize(this) aan om de beëindigingsoperatie van het object te annuleren; 3. Voeg een beschermde virtuele methode toe aan het type dat polymorfisme nodig heeft, en de afgeleide klasse laat zijn taak los door deze methode te herschrijven. 4. In het type dat een IDisoposable interface vereist, moeten we een terminator implementeren, ook al hebben we die niet nodig.
19. Definieer en implementeer interfaces over overervingstypen
1. Niet-gerelateerde types kunnen gezamenlijk een gemeenschappelijke interface implementeren, en het is makkelijker een interface te implementeren dan overerving; 2. De interface is relatief stabiel, het omvat een set functies in een interface zoals andere soorten implementatiecontracten, terwijl de basisklasse in de loop van de tijd kan worden uitgebreid.
20. Onderscheid maken tussen interface-implementatie en herschrijven van virtuele methoden
1. Bij het implementeren van een interface in de basisklasse moet de afgeleide klasse nieuw gebruiken om het gebruik van de basisklassemethode te verbergen; 2. De methode van de basisklasse-interface kan worden gedeclareerd als een virtuele methode en vervolgens worden geïmplementeerd in de afgeleide klasse.
21. Gebruik toevertrouwing om terugbellen uit te drukken
1. De delegate zelf biedt geen uitzonderingscapture, dus elke multicast delegate-oproep beëindigt de volledige callet. 2. Door elk delegatiedoel op de delegateketen weer te geven en aan te roepen, kun je voorkomen dat multicast-delegates alleen de output van de laatste delegate teruggeven.
22. Gebeurtenissen gebruiken om externe interfaces te definiëren
1. Het moet als een common event worden gedeclareerd, en de compiler moet add- en remove-methoden voor ons maken. 2. Gebruik de container: System.ComponentModel.EventHandlerList om elke event handler op te slaan, en gebruik deze om de complexiteit van alle events te verbergen wanneer het type een groot aantal events bevat.
23. Vermijd het teruggeven van referenties naar interne klasseobjecten
1. Aangezien de toegang van een waardetypeobject een kopie van het object creëert, zullen de attributen van het definiëren van een waardetype de toestand binnen het typeobject helemaal niet veranderen; 2. Constante types kunnen voorkomen dat de toestand van het object verandert; 3. Definieer de interface om de toegang tot een subset te beperken en zo schade aan de interne toestand van het object te minimaliseren. 4. Definieer een wrapperobject om de toegang tot een ander object te beperken; 5. Wanneer de klantcode de interne data-elementen verandert, kan de Observer-modus worden geïmplementeerd, zodat het object de wijzigingen kan verifiëren of ermee kan overeenkomen.
24. Declaratieve programmering is beter dan imperatief programmeren
De mogelijkheid om fouten te maken in meerdere vergelijkbare handgeschreven algoritmen kan worden vermeden en er wordt duidelijke en leesbare code geboden.
25. Implementeer types zo serialiseerbaar mogelijk.
1. Het type vertegenwoordigt geen UI-controle, venster of vorm, en het type moet serialisatie ondersteunen; 2. Bij het toevoegen van het deserialiseerde attribuut van NonSerializedAttribute kan de standaardwaarde worden geladen door de OnDeserialization()-methode die IDeserializationCallback implementeert; 3. In versiebeheer kun je de ISerializable-interface gebruiken voor flexibele controle, en een serialisatieconstructor bieden om objecten te initialiseren volgens de data in de stream, en ook de toestemming van SerializationFormatter-uitzonderingen vereisen bij implementatie. 4. Als je een afgeleide klasse moet maken, moet je een hook-methode voor de afgeleide klasse aanleveren.
26. Gebruik IComparable- en IComparer-interfaces om sorteerrelaties te implementeren
1. De IComparable-interface wordt gebruikt om de meest natuurlijke sorteerrelatie voor types te implementeren, waarbij vier vergelijkingsoperatoren worden overbelast en een overbelaste versie van de CompareTo()-methode worden geleverd om specifieke types als parameters te accepteren. 2. IComparer wordt gebruikt om sorteerrelaties te bieden die verschillen van IComparable, of om ons sorteerrelaties te geven waarvan het type zelf zegt dat ze niet zijn geïmplementeerd.
27. Vermijd ICloneable interfaces
1. Voor waardetypen is het niet nodig om ICloneable interface te ondersteunen, gebruik gewoon de standaard toewijzingsoperatie; 2. Voor basisklassen die mogelijk ICloneable-interfaces moeten ondersteunen, moet er een beschermde replicatieconstructor voor worden gemaakt, en IConeable-interfaces moeten worden vermeden.
28. Vermijd geforceerde conversie-operators
Het gebruik van constructors in plaats van conversie-operatoren kan het conversieproces duidelijker maken, wat gemakkelijk kan leiden tot vreemde bugs door tijdelijke objecten die na de conversie worden gebruikt.
29. Overweeg alleen de nieuwe modifier te gebruiken wanneer de opeenhoping van nieuwe versies problemen veroorzaakt
30. Implementeer CLS-compatibele assemblies zoveel mogelijk 1. Om een compatibele assembly te maken, moeten twee regels worden gevolgd: de parameters en retourwaardetypes die door alle publieke en beschermde leden van de assembly worden gebruikt, moeten compatibel zijn met CLS; Elk openbaar en beschermd lid dat niet compatibel is met de CLS, moet een CLS-compatibel alternatief hebben; 2. Je kunt de CLS-compatibiliteitstypecontrole omzeilen door expliciet de interface te implementeren, en de CLSCompliantAttribute zal de CLS-compatibiliteit van private leden niet controleren.
31. Voer zo veel mogelijk een korte en beknopte methode uit
1. De JIT-compiler compileert in eenheden van methoden, en methoden die niet worden aangeroepen worden niet door JIT gecompileerd; 2. Als de code van de Case-instructie in de langere Switch tegelijk wordt vervangen door één methode, wordt de tijd die door de JIT-compiler wordt bespaard vermenigvuldigd; 3. Korte en beknopte methoden en het selecteren van minder lokale variabelen kunnen geoptimaliseerd registergebruik bereiken; 4. Hoe minder controlevertakkingen in de methode, hoe gemakkelijker het is voor de JIT-compiler om variabelen in registers te plaatsen.
32. Streef zoveel mogelijk uit kleine afmetingen en hoge samenhangende assemblages
1. Alle publieke klassen en common base-klassen in enkele assemblies plaatsen, de toolklassen die functies voor public classes bieden in dezelfde assembly plaatsen, de relevante publieke interfaces in hun eigen assemblies verpakken, en tenslotte de klassen verwerken die zich overal op de horizontale positie in de applicatie bevinden; 2. In principe moeten er twee soorten componenten worden gemaakt: de ene is een kleine en geaggregeerde assemblage met een specifieke functie, en de andere is een grote en brede assemblage met gemeenschappelijke functies.
33. Beperk de zichtbaarheid van typen
1. Het gebruik van interfaces om de functies van types bloot te stellen kan het voor ons gemakkelijker maken om interne klassen te creëren zonder hun beschikbaarheid buiten de assembly te beperken; 2. Hoe minder publieke types je aan de buitenwereld blootstelt, hoe meer opties je hebt voor toekomstige uitbreiding en veranderingsimplementaties.
34. Een grote, gedetailleerde Web-API creëren
Dit minimaliseert de frequentie en belasting van transacties tussen machines, waardoor grote bewerkingen en fijnmazige uitvoeringen op de server worden toegepast.
35. Herschrijven is beter dan event processors
1. Als een eventprocessor een uitzondering gooit, worden andere processors in de event chain niet aangeroepen, maar dit gebeurt niet met de herschreven virtuele methode. 2. Herschrijven is veel efficiënter dan associatieve gebeurtenisprocessors, die over de hele verzoeklijst moeten itereren, wat meer CPU-tijd kost. 3. Gebeurtenissen kunnen tijdens runtime worden beantwoord, met meer flexibiliteit, en meerdere reacties kunnen aan hetzelfde event worden gekoppeld. 4. De gangbare regel is om te werken met een afgeleid gebeurtenis, en de herschrijfmethode is beter.
36. Fair use. .NET runtime diagnostiek
1. System.Diagnostics.Debug\Trace\EventLog biedt alle tools die nodig zijn om diagnostische informatie aan de runtime toe te voegen, en de applicatie kan naar het systeemgebeurtenislog schrijven wanneer de EventLog het ingrediënt levert; 2. Tot slot, schrijf niet je eigen diagnostische bibliotheek, .NET FCL heeft al de kernbibliotheek die we nodig hebben.
37. Gebruik standaard configuratiemechanismen
1、. De System.Windows.Application-klasse van het .NET-framework definieert de eigenschappen zodat we een gemeenschappelijk configuratiepad kunnen opstellen; 2. Application.LocalAppDataPath en Application.userDataPath genereren de padnamen van de lokale datamap en gebruikersgegevens; 3. Schrijf geen gegevens in ProgramFiles- en Windows-systeemmappen; deze locaties vereisen hogere beveiligingsrechten, verwacht niet dat gebruikers schrijfrechten hebben.
38. Aanpassen en ondersteunen van gegevensbinding
1. De twee objecten BindingMananger en CurrencyManager realiseren de gegevensoverdracht tussen de controle en de databron; 2. Voordelen van databinding: het gebruik van data binding is veel eenvoudiger dan het schrijven van je eigen code; Het moet worden gebruikt voor scopes anders dan tekstgegevensitems - andere weergave-eigenschappen kunnen ook worden begrensd; Voor Windowos Forms-databindings de mogelijkheid om meervoudige besturingssynchronisatie van controlegerelateerde databronnen te verwerken; 3. Wanneer het object de vereiste attributen niet ondersteunt, kun je databinding ondersteunen door het huidige object te blokkeren en vervolgens het gewenste object toe te voegen.
39. Gebruik. .NET-validatie
1. Er zijn vijf controles in de ASP.NET om de geldigheid te verifiëren, en je kunt CustomValidator gebruiken om een nieuwe klasse af te leiden om je eigen authenticator toe te voegen. 2. Windows-validatie vereist een sub-System.Windows.Forms.Control.Validating om een event handler te schrijven.
40. Kies de juiste ** op basis van de behoeften
1. De array heeft twee duidelijke gebreken: hij kan niet dynamisch worden verkleind; Grootteverandering kost veel tijd; 2. ArrayList combineert de kenmerken van eendimensionale arrays en gekoppelde lijsten, Queue en Stack zijn speciale arrays gebaseerd op Array; 3. Wanneer het programma flexibeler is in het toevoegen en verwijderen van items, kan het robuustere types maken, en bij het maken van een klasse die ** simuleert, zou het indexers en IEnumberable interfaces moeten implementeren.
41. Dataset is beter dan een aangepaste structuur
1. Datasets hebben twee nadelen: de interactie tussen Datasets met behulp van XML-serialisatiemechanisme en non-.NET code is niet erg goed; DataSet is een zeer veelzijdige container; 2. Sterke typen Datasets breken meer ontwerpregels, en hun ontwikkelefficiëntie is veel hoger dan die van de elegantere ontwerpen die ze zelf schrijven.
42. Gebruik kenmerken om reflectie te vereenvoudigen
Door featureklassen te ontwerpen en te implementeren die ontwikkelaars dwingen dynamisch bruikbare typen, methoden en attributen te declareren, kun je runtime-fouten in applicaties verminderen en de gebruikerstevredenheid van software verbeteren.
43. Vermijd overmatig gebruik van reflexen
1. De parameters en retourwaarden die door Invoke-leden worden gebruikt zijn System.Object, dat types tijdens runtime converteert, maar de kans op problemen is groter geworden. 2. De interface stelt ons in staat een duidelijker en beter onderhoudbaar systeem te krijgen, en reflectie is een zeer krachtig laatbindingsmechanisme. Het .NET-framework gebruikt het om databinding te implementeren voor Windows- en webbesturingselementen.
44. Specifieke uitzonderingsklassen aanmaken voor de applicatie
1. De enige reden waarom verschillende uitzonderingsklassen nodig zijn, is om gebruikers gemakkelijk verschillende benaderingen te laten gebruiken voor verschillende fouten bij het schrijven van catchprocessors; 2. Wanneer er mogelijk verschillende reparatiegedragingen zijn, moeten we verschillende uitzonderingsklassen creëren; door alle constructors te leveren die door de uitzonderingsbasisklasse worden ondersteund, kunnen we een volledig functionele uitzonderingsklasse voor de applicatie creëren en het InnerException-attribuut gebruiken om alle foutinformatie die wordt gegenereerd door laag-niveau foutvoorwaarden op te slaan.
45. Geef prioriteit aan abnormale veiligheidsgaranties
1. Sterke uitzonderingsgarantie biedt de beste balans tussen herstel van uitzondering en vereenvoudigde uitzonderingsbehandeling, en de status van het programma blijft ongewijzigd wanneer de operatie wordt onderbroken door de uitzondering. 2. Voer defensieve kopiëring uit van de te wijzigen data, wijzig de defensieve kopie van deze gegevens, de operatie in het midden kan een uitzondering veroorzaken, en de tijdelijke kopie en het originele object worden uitgewisseld; 3. Terminators, Dispose()-methoden en doelmethoden die aan gedelegeerden zijn gebonden, moeten ervoor zorgen dat ze onder geen enkele omstandigheid uitzonderingen gooien.
46. Minimaliseer interoperabiliteit
1. Er zijn drie kosten van interoperabiliteit: de kosten van data-enumeratie tussen beheerde en niet-beheerde heaps, de kosten van schakelen tussen beheerde code en onbeheerde code, en het ontwikkelingswerk van ontwikkelaars die werken met hybride omgevingen; 2. Het gebruik van het geblitable type in interop kan effectief heen en weer repliceren tussen beheerde en niet-beheerde omgevingen zonder beïnvloed te worden door de interne structuur van het object. 3. Gebruik de In/Out-functie om de meest geschikte onnodige meervoudige replicaties te garanderen, en verbeter de prestaties door aan te geven hoe de data wordt opgesomd. 4. COM Interop gebruiken om interoperabiliteit met COM-componenten op de eenvoudigste manier te implementeren, P/Invoke gebruiken om Win32 API aan te roepen, of de /CLR-switch van de C++-compiler gebruiken om beheerde en niet-beheerde code te combineren;
47. Geef prioriteit aan veiligheidsvoorschriften
1. Vermijd zoveel mogelijk toegang tot onbeheerd geheugen, en geïsoleerde opslag kan geen toegang van beheerde code en vertrouwde gebruikers verhinderen. 2. Wanneer assemblies op het web draaien, overweeg dan geïsoleerde opslag te gebruiken, en wanneer bepaalde algoritmen hogere beveiligingsrechten vereisen, moeten die codes geïsoleerd worden in een aparte assembly.
48. Beheers relevante hulpmiddelen en bronnen
1. Gebruik NUnit om automatische unittests op te zetten (geïntegreerd in VS2010); 2. De FXCop-tool zal de IL-code in de assembly verkrijgen, deze analyseren aan de hand van de heterogene coderingsregels en best practices, en uiteindelijk de overtreding rapporteren. 3. ILDasm is een IL-demontagetool die ons kan helpen inzicht te krijgen in details; 4. Shared Source CLI is een implementatiebroncode die de .NET frameworkkernel en de C#-compiler bevat. |