Pergunta

Ouço constantemente como é ruim usar a reflexão.Embora eu geralmente evite a reflexão e raramente encontre situações em que seja impossível resolver meu problema sem ela, fiquei pensando...

Para quem já usou reflexão em aplicações, você mediu os impactos de desempenho e é realmente tão ruim assim?

Foi útil?

Solução

Isso é.Mas isso depende do que você está tentando fazer.

Utilizo reflexão para carregar dinamicamente assemblies (plugins) e sua "penalidade" de desempenho não é um problema, já que a operação é algo que faço durante a inicialização da aplicação.

No entanto, se você estiver refletindo dentro de uma série de loops aninhados com chamadas de reflexão em cada um, eu diria que você deveria revisitar seu código :)

Para operações de "algum tempo", a reflexão é perfeitamente aceitável e você não notará nenhum atraso ou problema com ela.É um mecanismo muito poderoso e é usado até pelo .NET, então não vejo por que você não deveria tentar.

Outras dicas

Em sua palestra O desempenho das coisas cotidianas, Jeff Richter mostra que chamar um método por reflexão é sobre 1000 vezes mais lento do que ligar normalmente.

Dica do Jeff:se você precisar chamar o método várias vezes, use a reflexão uma vez para encontrá-lo e, em seguida, atribua-o a um delegar, e, em seguida, chame o delegado.

O desempenho da reflexão dependerá da implementação (chamadas repetitivas devem ser armazenadas em cache, por exemplo: entity.GetType().GetProperty("PropName")).Como a maior parte da reflexão que vejo diariamente é usada para preencher entidades de leitores de dados ou outras estruturas de tipo de repositório, decidi avaliar o desempenho especificamente na reflexão quando ela é usada para obter ou definir propriedades de objetos.

Elaborei um teste que considero justo, pois armazena em cache todas as chamadas repetidas e apenas cronometra a chamada SetValue ou GetValue real.Todo o código-fonte do teste de desempenho está no bitbucket em: https://bitbucket.org/grenade/accessortest.O escrutínio é bem-vindo e encorajado.

A conclusão a que cheguei é que não é prático e não fornece melhorias visíveis de desempenho para remover a reflexão em uma camada de acesso a dados que retorna menos de 100.000 linhas em um momento em que a implementação da reflexão é bem feita.

Graph of time (y) against number of entities populated(x)

O gráfico acima demonstra o resultado do meu pequeno benchmark e mostra que os mecanismos que superam a reflexão só o fazem visivelmente após a marca de 100.000 ciclos.A maioria dos DALs retorna apenas centenas ou talvez milhares de linhas por vez e, nesses níveis, a reflexão funciona perfeitamente.

Se você não está em apuros, não se preocupe.

Minha experiência mais pertinente foi escrever código para comparar quaisquer duas entidades de dados do mesmo tipo em um modelo de objeto grande em termos de propriedades.Fiz funcionar, tentei, corri como um cachorro, obviamente.

Fiquei desanimado e, da noite para o dia, percebi que, sem alterar a lógica, poderia usar o mesmo algoritmo para gerar automaticamente métodos para fazer a comparação, mas acessar estaticamente as propriedades.Não demorou muito para adaptar o código para esse propósito e tive a capacidade de fazer comparações profundas de entidades com código estático que poderia ser atualizado com o clique de um botão sempre que o modelo de objeto mudasse.

Meu ponto é:Em conversas com colegas, já apontei várias vezes que o uso da reflexão poderia ser para gerar automaticamente código para compilar, em vez de executar operações em tempo de execução, e isso geralmente vale a pena considerar.

Não massivamente.Nunca tive problemas com isso no desenvolvimento de desktop, a menos que, como afirma Martin, você o esteja usando em um local bobo.Já ouvi muitas pessoas terem medos totalmente irracionais sobre seu desempenho no desenvolvimento de desktops.

No Estrutura Compacta (no qual geralmente estou), porém, é praticamente anátema e deve ser evitado como uma praga na maioria dos casos.Ainda consigo usá-lo com pouca frequência, mas tenho que ter muito cuidado com sua aplicação, que é bem menos divertida.:(

Já é ruim o suficiente que você precise se preocupar até mesmo com a reflexão feita internamente pelas bibliotecas .NET para código de desempenho crítico.

O exemplo a seguir está obsoleto - verdadeiro na época (2008), mas corrigido há muito tempo em versões mais recentes do CLR.A reflexão em geral ainda é algo caro!

Caso em questão:Você nunca deve usar um membro declarado como "Object" em uma instrução lock (C#)/SyncLock (VB.NET) em código de alto desempenho.Por que?Como o CLR não pode bloquear um tipo de valor, o que significa que ele precisa fazer uma verificação do tipo de reflexão em tempo de execução para ver se o seu Object é ou não realmente um tipo de valor em vez de um tipo de referência.

Como acontece com todas as coisas na programação, você deve equilibrar o custo de desempenho com qualquer benefício obtido.A reflexão é uma ferramenta inestimável quando usada com cuidado.Criei uma biblioteca de mapeamento O/R em C# que usava reflexão para fazer as ligações.Isso funcionou fantasticamente bem.A maior parte do código de reflexão foi executada apenas uma vez, portanto, qualquer impacto no desempenho foi bem pequeno, mas os benefícios foram grandes.Se eu estivesse escrevendo um novo algoritmo de classificação em leque, provavelmente não usaria reflexão, pois provavelmente seria mal dimensionado.

Agradeço por não ter respondido exatamente à sua pergunta aqui.O que quero dizer é que isso realmente não importa.Use reflexão quando apropriado.É apenas mais um recurso de linguagem que você precisa aprender como e quando usar.

A reflexão pode ter um impacto perceptível no desempenho se você usá-la para criação frequente de objetos.Desenvolvi aplicativos baseados em Bloco de aplicativo de UI composto que depende fortemente da reflexão.Houve uma degradação perceptível no desempenho relacionada à criação de objetos via reflexão.

No entanto, na maioria dos casos, não há problemas com o uso da reflexão.Se sua única necessidade é inspecionar alguma montagem, eu recomendaria Mono.Cecil o que é muito leve e rápido

A reflexão é cara devido às muitas verificações que o tempo de execução deve fazer sempre que você faz uma solicitação para um método que corresponda a uma lista de parâmetros.Em algum lugar lá no fundo, existe um código que percorre todos os métodos de um tipo, verifica sua visibilidade, verifica o tipo de retorno e também verifica o tipo de cada parâmetro.Tudo isso custa tempo.

Quando você executa esse método internamente, há algum código que faz coisas como verificar se você passou uma lista compatível de parâmetros antes de executar o método de destino real.

Se possível, é sempre recomendável armazenar em cache o identificador do método, caso pretenda reutilizá-lo continuamente no futuro.Como todas as boas dicas de programação, muitas vezes faz sentido evitar a repetição.Nesse caso, seria um desperdício pesquisar continuamente o método com determinados parâmetros e executá-lo sempre.

Dê uma olhada na fonte e veja o que está sendo feito.

Como em tudo, trata-se de avaliar a situação.Em DotNetNuke há um componente bastante central chamado FillObject que usa reflexão para preencher objetos de linhas de dados.

Este é um cenário bastante comum e há um artigo no MSDN, Usando reflexão para vincular objetos de negócios a controles de formulário ASP.NET que cobre os problemas de desempenho.

Deixando de lado o desempenho, uma coisa que não gosto no uso da reflexão nesse cenário específico é que ela tende a reduzir a capacidade de entender o código rapidamente, o que para mim não parece valer o esforço quando você considera que também perde a compilação segurança de tempo em oposição a conjuntos de dados fortemente tipados ou algo como LINQ para SQL.

A reflexão não diminui drasticamente o desempenho do seu aplicativo.Você pode fazer certas coisas mais rapidamente se não usar a reflexão, mas se a reflexão for a maneira mais fácil de obter alguma funcionalidade, use-a.Você sempre pode refatorar seu código fora do Reflection se ele se tornar um problema de desempenho.

Acho que você descobrirá que a resposta é: depende.Não é grande coisa se você quiser colocá-lo em seu aplicativo de lista de tarefas.É um grande problema se você quiser colocá-lo na biblioteca de persistência do Facebook.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top