Imagine o código:
public class obj
{
// elided
}
public static Dictionary<string, obj> dict = new Dictionary<string, obj>();
Método 1
public static obj FromDict1(string name)
{
if (dict.ContainsKey(name))
{
return dict[name];
}
return null;
}
Método 2
public static obj FromDict2(string name)
{
try
{
return dict[name];
}
catch (KeyNotFoundException)
{
return null;
}
}
Fiquei curioso para saber se há uma diferença no desempenho dessas duas funções, porque a primeira DEVE SER MAIS LENTA que a segunda - uma vez que é necessário verificar duas vezes se o dicionário contém um valor, enquanto a segunda função precisa acessar apenas o dicionário uma vez, mas WOW, na verdade é o oposto:
Loop para 1 000 000 valores (sendo 100 000 existentes e 900 000 inexistentes):
primeira função: 306 milissegundos
segunda função: 20483 milissegundos
Por que é que?
EDIT: Como você pode notar nos comentários abaixo desta pergunta, o desempenho da segunda função é realmente um pouco melhor que o primeiro caso haja 0 chaves inexistentes. Porém, quando houver pelo menos uma ou mais chaves inexistentes, o desempenho da segunda diminuirá rapidamente.
fonte
ContainsKey
é esperadoO(1)
...O(1)
na pesquisa no dicionário ... Especialmente porque realizar duasO(1)
operações ainda é assintoticamenteO(1)
.Respostas:
Por um lado, lançar exceções é inerentemente caro , porque a pilha precisa ser desenrolada etc.
Por outro lado, acessar um valor em um dicionário por sua chave é barato, porque é uma operação O (1) rápida.
BTW: A maneira correta de fazer isso é usar
TryGetValue
Isso acessa o dicionário apenas uma vez em vez de duas vezes.
Se você realmente deseja apenas retornar
null
se a chave não existir, o código acima pode ser simplificado ainda mais:Isso funciona, porque
TryGetValue
defineitem
comonull
se nenhuma chavename
existe.fonte
Os dicionários são projetados especificamente para fazer pesquisas de teclas super rápidas. Eles são implementados como hashtables e quanto mais entradas, mais rápido elas são em relação a outros métodos. O uso do mecanismo de exceção só deve ser feito quando seu método falhar em fazer o que você o projetou, porque é um grande conjunto de objetos que oferece muitas funcionalidades para lidar com erros. Eu construí uma classe de biblioteca inteira uma vez com tudo cercado por blocos try try uma vez e fiquei chocado ao ver a saída de depuração que continha uma linha separada para cada uma das mais de 600 exceções!
fonte