
Certa vez me deparei com o problema de criar dicionários onde as chaves fossem Case-Insensitive, isto é, dicionários onde a chave “nda” fosse considerada a mesma chave “NdA”.
Existem diversos cenários onde este comportamento é desejável. Imagine, por exemplo, um dicionário que contém o mapeamento nomeDoCampo para ObjetoCampo, que é usado para representar todos o campos de um objeto formulário.
Se nas regras de negócio o nome do campo for Case-Sensitive, isto é, o campo nomeado “Campo01″ for considerado diferente do campo nomeado “CAMPO01″, não existe segredo, basta usar um Hashtable ou um Dictionary genérico que o problema estará sanado.
Se, pelo contrário, as regras definirem que os nomes de campo “campo01″ e “CAMPO01″ devem se tratar do mesmo objeto, então seu dicionário, o qual irá conter esse mapeamento, precisa de um comportamento diferenciado.
Vamos ver como seria o trabalho de verificar se um dado campo, supondo que no nome do campo seja case-insensitive, está presente em um dicionário normal, juntamente com a operação de adição de um novo campo.
static Hashtable campos = new Hashtable();
static void insiraCampo(string nome, object campo)
{
if (!campoExiste(nome))
campos.Add(nome, campo);
}
static bool campoExiste(string nomeDoCampo)
{
foreach (DictionaryEntry entrada in campos)
{
if (entrada.Key.ToString().ToUpper().Equals(nomeDoCampo.ToUpper()))
return true;
}
return false;
}
Veja o mesmo exemplo onde a variável campos é um dicionário Case-Insensitive
static Hashtable camposInsensitive = CollectionsUtil.CreateCaseInsensitiveHashtable();
static void insiraCampoCaseInsensitive(string nome, object campo)
{
if (!campos.ContainsKey(nome))
campos.Add(nome, campo);
}
/*
O método campoExiste(string nomeDoCampo) não é mais necessário, basta invocar campos.ContainsKey(nomeDoCampo) para obter o resultado.
*/
O ganho não é apenas na menor quantidade de linhas de código e de um melhor aproveitamento da API .NET, uma das principais vantagens é também o desempenho.
Vejam abaixo as diferenças entre os tempos de inserção usando as duas formas:
|
Quantidade de Itens Inseridos |
100 |
1000 |
5000 |
10000 |
|
|
Tempo |
Hashtable normal (ms) |
156250 |
650000 |
196093750 |
930468750 |
|
Tempo |
Hashtable Case-Insensitive(ms) |
0 |
0 |
0 |
312500 |
Baixe o código de testes clicando aqui.
Configurações da máquina de Testes:
-
1.75 GB de Memória RAM
-
Processador AMD Athlon 64 x2 - Dual Core Processor TK-53
// Forma padrão de se criar um Hashtable Case Insensitive
Hashtable insensitive = CollectionsUtil.CreateCaseInsensitiveHashtable();
/*
Criação de um Hashtable Case Insensitive informando o número máximo de entradas que o objeto suporta.
*/
Hashtable insensitive2 = CollectionsUtil.CreateCaseInsensitiveHashtable(1000);
/*
Criação de um Hashtable Case Insensitive baseado em um Dicionário existente
o dicionário recebido com argumento é não-genérico, mas caso deseje realizar essa operação com um dicionário genérico basta fazer o cast que funcionará corretamente.
*/
IDictionary<object, string> dicionario = new Dictionary<object, string>();
dicionario.Add(”chave01″, “Qualquer coisa”);
dicionario.Add(”Chave01″, “Outra Coisa”);
dicionario.Add(”chave02″, “Qualquer coisa denovo”);
dicionario.Add(”Chave02″, “Mais uma coisa”);
// Dispara um ArgumentException
Hashtable insensitive3 = CollectionsUtil.CreateCaseInsensitiveHashtable(dicionario as IDictionary);
No próximo post irei falar um pouco sobre a manipulação Case-Insensitive de outros tipos de Coleções.
Espero ter contribuído, e fiquem a vontade para comentar e questionar sobre este post!
Abraços
[...] Maio , 2008 de Frederico Policarpo Martins Neste artigo vou falar um pouco de como trabalhar com Case-Insensitive em Listas, como havia combinado no artigo anterior. [...]