Este artigo é um artigo espelhado de tradução automática, por favor clique aqui para ir para o artigo original.

Vista: 20516|Resposta: 0

[Gorjetas] Quarenta e sete maneiras de otimizar um programa C#

[Copiar link]
Publicado em 15/03/2018 10:41:59 | | |

1. Substituir campos acessíveis por atributos

1、. A vinculação de dados .NET suporta apenas vinculação de dados, e você pode obter os benefícios da vinculação de dados usando atributos.
2. No acesso get and set à propriedade, você pode usar lock para adicionar suporte a multithreading.

2. apenas leitura (constante de tempo de runtime) e const (constante de tempo de compilação)

1. const só pode ser usado para tipos primitivos, enums e strings, enquanto o somente leitura pode ser de qualquer tipo;
2. Const será substituída por uma constante específica em tempo de compilação, de modo que, se tanto valores const quanto lei-somente usados na referência, a mudança para read-only alterará a intenção original do projeto, que é a necessidade de recompilar o assembly alterado para rereferenciar o novo valor constante.
3. Const é mais eficiente que apenas leitura, mas perde a flexibilidade de aplicação.

3. IS e AS

1. Ambos são conversões de tipo em tempo de execução, pois operadores só podem ser usados em tipos de referência, enquanto is pode usar valores e tipos de referência;
2. A prática usual é usar IS para determinar o tipo e, em seguida, escolher usar como ou um operador de conversão de tipo forte (conversão definida por um operador) seletivamente.

4. ConditionalAttribute em vez de #if #endif条件编译

1. ConditionalAttribute é usado apenas no nível do método, e outros itens como tipos, atributos, etc., são inválidos. E #if #endif则不受此限制;
2. ConditionalAttribute pode adicionar múltiplas operações OR (OR) para condições de compilação, e #if #endif则可以添加与(AND) [aqui pode ser completamente definido como outro símbolo separado];
3. A definição ConditioanlAttribute pode ser colocada em um método separado para tornar o programa mais flexível.

5. Forneça o método ToString()

1. Pode fornecer informações detalhadas aos usuários de forma mais amigável;
2. Use o método IFormatter.ToString() para oferecer uma personalização mais flexível, e se você adicionar as interfaces IFormatProvider e ICustomFormatter, fará mais sentido personalizar a saída da mensagem.

6. A diferença entre valor e tipo de referência

1. Tipos de valor não suportam polimorfismo, que é adequado para armazenar dados operados por aplicações, enquanto referências suportam polimorfismo, que é adequado para definir o comportamento das aplicações.
2. Para arrays definidos como tipos de valor, o desempenho do programa pode ser significativamente melhorado;
3. O tipo de valor apresenta menos fragmentação de memória de heap, lixo de memória e tempo de acesso indireto, e seu retorno no método é feito na forma de replicação para evitar expor a estrutura interna ao mundo externo.
4. Tipos de valor são usados nos seguintes cenários: As responsabilidades dos tipos são principalmente usadas para armazenamento de dados; Interfaces públicas são completamente definidas por alguns atributos de acesso aos membros dos dados; Nunca existem subclasses; Nunca há comportamento polimórfico.

7. Os tipos de valor devem ser implementados como constantes e os tipos atômicos possível

1. Tornar nosso código mais fácil de escrever e manter;
2. Três estratégias para inicializar constantes: na construção; método de plantas; Construa uma classe auxiliar mutável (por exemplo, StringBuilder).

8. Garantir que 0 seja digno de status válido

1. O estado padrão do tipo de valor deve ser 0;
2. O 0 do tipo enum não deve ser inválido; No FlagsAttribute é para garantir que o valor 0 seja válido no estado;
3. Quando a cadeia está vazia, uma cadeia pode ser retornada. fio vazio para vazio.

9. Múltiplas relações de representação de julgamento igual

1. ReferenceEquals() determina que as referências são iguais, e precisa ser verdadeiro quando ambas se referem ao mesmo objeto.
2. O método estático Equals() é usado para fazer julgamento de referência primeiro e, em seguida, para julgar o tipo de valor;
3. Para o julgamento do tipo de referência, você pode usar o método rewrite Equals() ao usar semântica de valores.
4. Ao reescrever o método Equals(), o método GetHashCode() também deve ser reescrito, e a operação operater==() deve ser fornecida ao mesmo tempo.

10. Compreender as limitações do método GetHashCode()

1. GetHashCode() é aplicado apenas a valores hash de chaves definidas em ** baseadas em hash, como HashTable ou Dicionário;
2. GetHashCode() deve seguir as três regras correspondentes: dois objetos iguais devem devolver o mesmo código hash; deve ser um invariante de instância; A função hash deve produzir uma distribuição aleatória entre todos os inteiros.

11. Dê prioridade ao uso de instruções foreach loop

1. foreach pode eliminar a verificação do compilador da fronteira do array do loop for;
2. A variável circular de foreach é somente leitura, e há uma transformação explícita, que cria uma exceção quando o tipo de objeto do objeto ** está incorreto;
3. O ** necessário para foreach é: ter o método público GetEnumberator(); A interface IEnumberable é explicitamente implementada. A interface IEnumerator é implementada;
4. foreach pode trazer benefícios do gerenciamento de recursos, porque se o compilador conseguir determinar a interface IDisposável, ele pode usar o try... otimizado... finalmente bloquear;

12. A inicialização do campo padrão é melhor do que a instrução de atribuição

1. A vida útil do campo inicializará o tipo de valor para 0 e o tipo de referência para nulo por padrão.
2. Inicializar o mesmo objeto várias vezes reduzirá a eficiência de execução do código.
3. Colocar a inicialização do corpo no construtor é propício ao tratamento de exceções.

13. Use o construtor estático para inicializar membros estáticos

1. O construtor estático será executado antes que qualquer método, variável ou atributo de uma classe seja acessado;
2. Campos estáticos também executam antes do construtor estático, e o construtor estático é propício ao tratamento de exceções.

14. Use a cadeia construtora (em. NET 4.0 já resolve esse problema com parâmetros opcionais)

1. Use isso para entregar o trabalho de inicialização a outro construtor, e use base para chamar o construtor da classe base;
2. A sequência de operações das instâncias de tipo é: definir todos os campos estáticos em 0; Execução de inicializadores de campo estático; um construtor estático que executa a classe base; Construtores estáticos que executam o tipo atual;
Defina todos os campos de instância para 0; Inicializadores de campos de instância de execução; Executar o construtor de instância da classe base apropriado; Execute o construtor de instância do tipo atual.

15. Use as instruções using e try/finally para limpar recursos

No método Dispose() da interface IDisposable, o GC.SuppressFinalize() pode ser usado para notificar o coletor de lixo que a operação final não foi mais realizada.

16. Minimizar o lixo de memória

1. Leva tempo extra do processador para alocar e destruir objetos em um heap;
2. Técnicas para reduzir o número de objetos atribuídos: variáveis locais frequentemente usadas são promovidas a campos; Fornece uma classe que armazena instâncias comuns de objetos Singleton que expressam tipos específicos.
3. Usar o StringBuilder para realizar operações complexas de strings.

17. Minimize a embalagem e o desempacotamento

1. Preste atenção à conversão implícita de um tipo para System.Object, e o tipo de valor não deve ser substituído pelo tipo System.Object;
2. Usar interfaces em vez de tipos pode evitar o boxing, ou seja, implementar tipos de valor a partir de interfaces e depois chamar membros por meio de interfaces.

18. Implementar o modo padrão Descarte

1. Para usar recursos que não sejam de memória, ele deve ter um finalizador, o coletor de lixo adicionará os objetos finalizadores implementados à fila de terminação após completar os objetos de memória que não os terminaram, e então o coletor de lixo iniciará uma nova thread para executar os finalizadores nesses objetos. Isso pode evitar o problema de vazamento de memória causado por recursos de memória não gerenciados que não são liberados.
2. Usar o método IDisposable.Dispose() requer quatro aspectos do trabalho: liberar todos os recursos não gerenciados; Libere todos os recursos gerenciados; Defina um marcador de status para indicar se o Dispose() foi executado; Chame GC.SuppressFinalize(this) para cancelar a operação de terminação do objeto;
3. Adicionar um método virtual protegido Dispose() ao tipo que precisa de polimorfismo, e a classe derivada libera sua tarefa reescrevendo esse método.
4. No tipo que exige uma interface IDisoposável, devemos implementar um exterminador mesmo que não precisemos de um.

19. Definir e implementar interfaces sobre tipos de herança

1. Tipos não relacionados podem implementar conjuntamente uma interface comum, e é mais fácil implementar uma interface do que a herança;
2. A interface é relativamente estável, ela encapsula um conjunto de funções em uma interface conforme outros tipos de implementação se contraem, enquanto a classe base pode ser estendida ao longo do tempo.

20. Distinção entre implementação de interface e reescrita de métodos virtuais

1. Ao implementar uma interface na classe base, a classe derivada precisa usar new para ocultar o uso do método da classe base;
2. O método da interface da classe base pode ser declarado como um método virtual e então implementado na classe derivada.

21. Usar a confiança para expressar callbacks

1. O próprio delegado não fornece captura de exceção, então qualquer chamada de delegado multicast encerrará toda a cadeia de chamadas.
2. Ao exibir e chamar cada destino de delegação na cadeia de delegados, você pode evitar que delegados multicast retornem apenas a saída do último delegado.

22. Usar eventos para definir interfaces externas

1. Deve ser declarado como um evento comum, e deixar o compilador criar métodos de adição e remoção para nós.
2. Use o contêiner System.ComponentModel.EventHandlerList para armazenar cada handler de eventos, e utilize-o para ocultar a complexidade de todos os eventos quando o tipo contém um grande número de eventos.

23. Evite retornar referências a objetos internos de classe

1. Como o acesso a um objeto tipo valor criará uma cópia do objeto, os atributos de definir um tipo de valor não alterarão o estado dentro do objeto tipo;
2. Tipos constantes podem evitar alterar o estado do objeto;
3. Defina a interface para limitar o acesso a um subconjunto e minimizar o dano ao estado interno do objeto.
4. Defina um objeto wrapper para restringir o acesso a outro objeto;
5. Quando o código do cliente altera os elementos de dados internos, o modo Observador pode ser implementado, para que o objeto possa verificar ou corresponder às alterações.

24. Programação declarativa é melhor que programação imperativa

A possibilidade de cometer erros em múltiplos algoritmos manuscritos semelhantes pode ser evitada e código claro e legível é fornecido.

25. Implementar tipos o mais serializáveis possível

1. O tipo não representa um controle, janela ou formulário de interface, e o tipo deve suportar serialização;
2. Ao adicionar o atributo deserializado de NonSerializedAttribute, o valor padrão pode ser carregado pelo método OnDeserialization() que implementa IDeserializationCallback;
3. No controle de versão, você pode usar a interface ISerializable para controle flexível, fornecer um construtor de serialização para inicializar objetos de acordo com os dados no fluxo, além de exigir a permissão das exceções SerializationFormatter ao implementar.
4. Se você precisa criar uma classe derivada, precisa fornecer um método de gancho para a classe derivada.

26. Usar interfaces IComparable e IComparer para implementar relações de ordenação

1. A interface IComparable é usada para implementar a relação de ordenação mais natural para tipos, sobrecarregando quatro operadores de comparação e fornecendo uma versão sobrecarregada do método CompareTo() para aceitar tipos específicos como parâmetros.
2. O IComparer é usado para fornecer relações de ordenação diferentes do IComparable, ou para nos fornecer relações de ordenação que o próprio tipo diz não serem implementadas.

27. Evitar interfaces isoladas

1. Para tipos de valor, não há necessidade de suportar interface ICloneable, basta usar a operação padrão de atribuição;
2. Para classes base que possam precisar suportar interfaces ICloneáveis, um construtor de replicação protegido deve ser criado para elas, e interfaces IConeáveis devem ser evitadas.

28. Evitar operadores de conversão forçada

Usar construtores em vez de operadores de conversão pode tornar o trabalho de conversão mais claro, o que pode facilmente levar a bugs estranhos devido a objetos temporários usados após a conversão.

29. Só considere usar o novo modificador quando o acúmulo de novas versões causar problemas

30. Implementar assemblies compatíveis com CLS o máximo possível
1. Para criar um assembly compatível, duas regras precisam ser seguidas: os parâmetros e tipos de valor de retorno usados por todos os membros públicos e protegidos do assembly devem ser compatíveis com CLS; Qualquer membro público e protegido que não seja compatível com o CLS deve ter uma alternativa compatível com o CLS;
2. Você pode contornar a verificação de tipo de compatibilidade CLS implementando explicitamente a interface, e o CLSCompliantAttribute não verificará a compatibilidade CLS dos membros privados.

31. Implementar um método curto e conciso tanto quanto possível

1. O compilador JIT compila em unidades de métodos, e métodos que não são chamados não serão compilados por JIT;
2. Se o código da instrução Case no Switch mais longo for substituído por um método por vez, o tempo economizado pelo compilador JIT será multiplicado;
3. Métodos curtos e concisos e a seleção de menos variáveis locais podem obter uso otimizado dos registradores;
4. Quanto menos desvios de controle no método, mais fácil será para o compilador JIT colocar variáveis em registradores.

32. Realizar conjuntos de tamanho pequeno e alta coesão tanto quanto possível

1. Colocar todas as classes públicas e classes base comuns em alguns assemblies, colocar as classes de ferramentas que fornecem funções para classes públicas no mesmo assembly, empacotar as interfaces públicas relevantes em seus próprios assemblies e, finalmente, processar as classes que estão espalhadas pela posição horizontal na aplicação;
2. Em princípio, dois tipos de componentes devem ser criados: um é um conjunto pequeno e agregado com uma função específica, e o outro é um conjunto grande e amplo com funções comuns.

33. Limitar a visibilidade dos tipos

1. Usar interfaces para expor as funções dos tipos pode facilitar a criação de classes internas sem limitar sua disponibilidade fora do monte;
2. Quanto menos tipos públicos estiverem expostos ao mundo exterior, mais opções você terá para futuras expansões e implementações de mudanças.

34. Criar uma API Web de grande granulação

Isso minimiza a frequência e a carga das transações entre máquinas, colocando grandes operações e execuções detalhadas no servidor.

35. Reescrita é melhor do que processadores de eventos

1. Se um processador de eventos lançar uma exceção, outros processadores na cadeia de eventos não serão chamados, mas isso não acontecerá com o método virtual reescrito.
2. Reescrever é muito mais eficiente do que processadores de eventos associativos, que precisam iterar sobre toda a lista de requisições, o que consome mais tempo de CPU.
3. Eventos podem ser respondidos em tempo de execução, com mais flexibilidade, e múltiplas respostas podem ser associadas ao mesmo evento.
4. A regra comum é lidar com um evento derivado, e o método de reescrita é melhor.

36. Uso justo. Diagnósticos de runtime do .NET

1. System.Diagnostics.Debug\Trace\EventLog fornece todas as ferramentas necessárias para que o programa adicione informações de diagnóstico ao tempo de execução, e a aplicação pode gravar no registro de eventos do sistema quando o EventLog fornece o ingrediente;
2. Por fim, não escreva sua própria biblioteca de diagnóstico, o .NET FCL já tem a biblioteca central que precisamos.

37. Utilizar mecanismos de configuração padrão

1、. A classe System.Windows.Application do framework .NET define as propriedades para que possamos estabelecer um caminho de configuração comum;
2. Application.LocalAppDataPath e Application.userDataPath gerarão os nomes de caminhos do diretório local de dados e dados de usuário;
3. Não escreva dados em ProgramFiles e diretórios do sistema Windows, esses locais exigem permissões de segurança mais altas, não espere que os usuários tenham permissões de escrita.

38. Personalizar e suportar binding de dados

1. Os dois objetos do BindingGestionnaire e do CurrencyManager realizam a transferência de dados entre o controle e a fonte de dados;
2. Vantagens da vinculação de dados: usar vinculação de dados é muito mais simples do que escrever seu próprio código; Deve ser usado para escopos que não sejam itens de dados de texto – outras propriedades de exibição também podem ser limitadas; Para os acadênculos de dados do WindowOS Forms, a capacidade de lidar com sincronização múltipla de controles de fontes de dados relacionadas à verificação;
3. Quando o objeto não suporta os atributos exigidos, você pode suportar a vinculação de dados bloqueando o objeto atual e depois adicionando o objeto desejado.

39. Use. Validação .NET

1. Existem cinco controles no ASP.NET para verificar a validade, e você pode usar o CustomValidator para derivar uma nova classe e adicionar seu próprio autenticador.
2. A validação do Windows requer um sub-System.Windows.Forms.Control.Validating para escrever um gerenciador de eventos.

40. Escolha o ** apropriado de acordo com as necessidades

1. O array apresenta dois defeitos óbvios: não pode ser redimensionado dinamicamente; Redimensionar é demorado;
2. ArrayList mistura as características de arrays unidimensionais e listas enlaçadas, Queue e Stack são arrays especiais baseados em Array;
3. Quando o programa é mais flexível para adicionar e excluir itens, ele pode criar tipos mais robustos e, ao criar uma classe que simula **, deve implementar indexadores e interfaces IEnumberables para ela.

41. DataSet é melhor do que estrutura personalizada

1. Os DataSets têm duas desvantagens: a interação entre DataSets usando o mecanismo de serialização XML e o código non-.NET não é muito boa; O DataSet é um contêiner muito versátil;
2. Tipos fortes de DataSets quebram mais regras de design, e sua eficiência de desenvolvimento é muito maior do que a dos designs mais elegantes escritos por eles mesmos.

42. Use características para simplificar a reflexão

Ao projetar e implementar classes de recursos que forçam os desenvolvedores a declarar tipos, métodos e atributos utilizáveis dinamicamente, você pode reduzir erros em tempo de execução da aplicação e melhorar a satisfação dos usuários de software.

43. Evite usar reflexos em excesso

1. Os parâmetros e valores de retorno usados pelos membros do Invoke são System.Object, que converte tipos em tempo de execução, mas a possibilidade de problemas tornou-se mais provável.
2. A interface nos permite obter um sistema mais claro e fácil de manter, e a reflexão é um mecanismo muito poderoso de ligação tardia. O .NET framework o utiliza para implementar vinculação de dados para controles do Windows e web.

44. Criar classes de exceção específicas para a aplicação

1. A única razão pela qual diferentes classes de exceção são necessárias é permitir que os usuários adotem facilmente abordagens diferentes para diferentes erros ao escrever processadores catch;
2. Quando podem existir diferentes comportamentos de reparo, devemos criar uma variedade de diferentes classes de exceção; fornecendo todos os construtores suportados pela classe base de exceção, podemos criar uma classe de exceção totalmente funcional para a aplicação e usar o atributo InnerException para salvar todas as informações de erro geradas por condições de erro de nível inferior.

45. Dar prioridade a garantias anormais de segurança

1. A forte garantia de exceção oferece o melhor equilíbrio entre recuperação de exceções e tratamento simplificado de exceções, e o estado do programa permanece inalterado quando a operação é interrompida devido à exceção.
2. Fazer cópia defensiva dos dados a serem modificados, modificar a cópia defensiva desses dados, a operação no meio pode causar uma exceção, e a cópia temporária e o objeto original serão trocados;
3. Métodos Terminators, Dispose() e métodos alvo vinculados aos delegados devem garantir que não joguem exceções sob nenhuma circunstância.

46. Minimizar a interoperabilidade

1. Existem três custos de interoperabilidade: o custo da enumeração de dados entre heaps gerenciados e não gerenciados, o custo de alternância entre código gerenciado e código não gerenciado, e o trabalho de desenvolvimento de desenvolvedores lidando com ambientes híbridos;
2. O uso do tipo blittable na interoperabilidade pode replicar efetivamente entre ambientes gerenciados e não gerenciados sem ser afetado pela estrutura interna do objeto.
3. Use o recurso In/Out para garantir as replicações múltiplas desnecessárias mais apropriadas e melhore o desempenho declarando como os dados são enumerados.
4. Usar interoperabilidade COM para implementar interoperabilidade com componentes COM da forma mais simples, usar P/Invoke para chamar a API Win32, ou usar o switch /CLR do compilador C++ para misturar código gerenciado e não gerenciado;

47. Dar prioridade aos códigos de segurança

1. Evite acessar memória não gerenciada tanto quanto possível, e o armazenamento isolado não pode impedir o acesso de código gerenciado e usuários confiáveis.
2. Quando assemblies rodam na web, considere usar armazenamento isolado, e quando certos algoritmos exigem permissões de segurança mais altas, esses códigos devem ser isolados em um assembly separado.

48. Domine ferramentas e recursos relevantes

1. Usar o NUnit para estabelecer testes unitários automáticos (integrados no VS2010);
2. A ferramenta FXCop obterá o código IL na montagem, o analisará em relação às regras e melhores práticas de codificação heterogêneas, e finalmente reportará a violação.
3. ILDasm é uma ferramenta de desmontagem de IL que pode nos ajudar a obter insights sobre detalhes;
4. Shared Source CLI é um código-fonte de implementação que contém o kernel do .NET framework e o compilador C#.




Anterior:Estrutura de Serviço - conceito de Serviço Estadual
Próximo:.net/c# SynchronizationContext para detalhes
Disclaimer:
Todo software, material de programação ou artigos publicados pela Code Farmer Network são apenas para fins de aprendizado e pesquisa; O conteúdo acima não deve ser usado para fins comerciais ou ilegais, caso contrário, os usuários terão todas as consequências. As informações deste site vêm da Internet, e disputas de direitos autorais não têm nada a ver com este site. Você deve deletar completamente o conteúdo acima do seu computador em até 24 horas após o download. Se você gosta do programa, por favor, apoie um software genuíno, compre o registro e obtenha serviços genuínos melhores. Se houver qualquer infração, por favor, entre em contato conosco por e-mail.

Mail To:help@itsvse.com