Quero tentar converter uma string em um Guid, mas não quero depender de exceções de captura (
- por razões de desempenho - as exceções são caras
- por motivos de usabilidade - o depurador é exibido
- por motivos de design - o esperado não é excepcional
Em outras palavras, o código:
public static Boolean TryStrToGuid(String s, out Guid value)
{
try
{
value = new Guid(s);
return true;
}
catch (FormatException)
{
value = Guid.Empty;
return false;
}
}
Não é adequado.
Eu tentaria usar o RegEx, mas como o guid pode ser empacotado entre parênteses, empacotado entre chaves, nenhum empacotado, fica difícil.
Além disso, pensei que certos valores de Guid são inválidos (?)
Atualização 1
ChristianK teve uma boa idéia para capturar apenas FormatException
, e não todos. O exemplo de código da pergunta foi alterado para incluir sugestão.
Atualização 2
Por que se preocupar com exceções lançadas? Estou realmente esperando GUIDs inválidos com tanta frequência?
A resposta é sim . É por isso que estou usando o TryStrToGuid - estou esperando dados ruins.
Exemplo 1 As extensões de espaço para nome podem ser especificadas anexando um GUID a um nome de pasta . Talvez eu esteja analisando os nomes das pastas, verificando se o texto após a final . é um GUID.
c:\Program Files
c:\Program Files.old
c:\Users
c:\Users.old
c:\UserManager.{CE7F5AA5-6832-43FE-BAE1-80D14CD8F666}
c:\Windows
c:\Windows.old
Exemplo 2 Talvez eu esteja executando um servidor da Web muito usado e queira verificar a validade de alguns dados publicados de volta. Não quero que dados inválidos vinculem recursos de 2 a 3 ordens de magnitude maiores do que precisam.
Exemplo 3 Talvez eu esteja analisando uma expressão de pesquisa inserida por um usuário.
Se eles digitarem GUIDs, desejo processá-los especialmente (como pesquisar especificamente por esse objeto ou realçar e formatar esse termo de pesquisa específico no texto de resposta).
Atualização 3 - Benchmarks de desempenho
Teste a conversão de 10.000 Guids bons e 10.000 Guids ruins.
Catch FormatException:
10,000 good: 63,668 ticks
10,000 bad: 6,435,609 ticks
Regex Pre-Screen with try-catch:
10,000 good: 637,633 ticks
10,000 bad: 717,894 ticks
COM Interop CLSIDFromString
10,000 good: 126,120 ticks
10,000 bad: 23,134 ticks
ps Eu não deveria ter que justificar uma pergunta.
4.0
. É por isso que a pergunta e a resposta aceita são do jeito que são.Respostas:
Benchmarks de desempenho
Resposta Intertop (mais rápida) COM:
Conclusão: se você precisar verificar se uma sequência é um guia e se preocupa com o desempenho, use a Interoperabilidade COM.
Se você precisar converter um guia na representação String em um Guia, use
fonte
Quando o .net 4.0 estiver disponível, você poderá usá-lo
Guid.TryParse()
.fonte
Você não vai gostar disso, mas o que faz você pensar que capturar a exceção será mais lento?
Quantas tentativas fracassadas de analisar um GUID você espera em comparação com as bem-sucedidas?
Meu conselho é usar a função que você acabou de criar e criar um perfil do seu código. Se você achar que essa função é realmente um ponto de acesso , corrija-a, mas não antes.
fonte
No .NET 4.0, você pode escrever da seguinte maneira:
fonte
Eu pelo menos reescreveria como:
Você não deseja dizer "GUID inválido" em SEHException, ThreadAbortException ou outros itens fatais ou não relacionados.
Atualização : A partir do .NET 4.0, há um novo conjunto de métodos disponíveis para o Guid:
Guid.TryParse
Guid.TryParseExact
Realmente, eles devem ser usados (mesmo que não sejam implementados de forma "ingênua" usando internamente o try-catch).
fonte
A interoperabilidade é mais lenta do que apenas capturar a exceção:
No caminho feliz, com 10.000 Guids:
No caminho infeliz:
É mais consistente, mas também consistentemente mais lento. Parece-me que seria melhor configurar seu depurador para interromper apenas exceções não tratadas.
fonte
Bem, aqui está o regex que você precisará ...
Mas isso é apenas para iniciantes. Você também precisará verificar se as várias partes, como a data / hora, estão dentro dos limites aceitáveis. Não consigo imaginar que isso seja mais rápido que o método try / catch que você já descreveu. Espero que você não esteja recebendo tantos GUIDs inválidos para garantir esse tipo de verificação!
fonte
Se você estiver adotando a abordagem try / catch, poderá adicionar o atributo [System.Diagnostics.DebuggerHidden] para garantir que o depurador não quebre, mesmo que você o tenha configurado para lançamento.
fonte
Enquanto ele seja verdade que o uso de erros seja mais caro, a maioria das pessoas acredita que a maioria de seus GUIDs será gerada por computador; portanto, isso
TRY-CATCH
não é muito caro, pois gera apenas o custoCATCH
. Você pode provar isso para si mesmo com um teste simples dos dois (público do usuário, sem senha).Aqui está:
fonte
Eu tive uma situação semelhante e notei que quase nunca a string inválida tinha 36 caracteres. Portanto, com base nesse fato, alterei um pouco o seu código para obter melhor desempenho, mantendo-o simples.
fonte
Até onde eu sei, não há algo como Guid.TryParse no mscrolib. De acordo com a fonte de referência, o tipo Guid possui um construtor de mega-complexo que verifica todos os tipos de formatos de guia e tenta analisá-los. Não existe um método auxiliar que você possa chamar, mesmo através da reflexão. Eu acho que você precisa procurar por analisadores Guid de terceiros ou escrever seus próprios.
fonte
Execute o GUID potencial por meio de um RegEx ou algum código personalizado que faça uma verificação de integridade para garantir que o strig pareça pelo menos um GUID e consista apenas em caracteres válidos (e talvez pareça se adequar ao formato geral). Se não passar na verificação de sanidade, retorne um erro - que provavelmente eliminará a grande maioria das seqüências inválidas.
Em seguida, converta a sequência conforme descrito acima, ainda capturando a exceção para as poucas sequências inválidas que passam pela verificação de sanidade.
Jon Skeet fez uma análise para algo semelhante para analisar Ints (antes do TryParse estar no Framework): Verificando se uma string pode ser convertida em Int32
No entanto, como AnthonyWJones indicou, você provavelmente não deveria se preocupar com isso.
fonte
fonte
O ctor de Guid é praticamente um regex compilado, dessa forma você obtém exatamente o mesmo comportamento sem sobrecarga da exceção.
Uma solução ainda mais legal seria instrumentar dinamicamente um método, substituindo "jogar novo" rapidamente.
fonte
Eu voto no link GuidTryParse postado acima por Jon ou em uma solução semelhante (IsProbablyGuid). Escreverei um como os da minha biblioteca de conversões.
Eu acho que é totalmente idiota que essa questão tenha que ser tão complicada. A palavra-chave "is" ou "as" seria adequada se um Guid pudesse ser nulo. Mas, por algum motivo, mesmo que o SQL Server esteja de acordo, o .NET não. Por quê? Qual é o valor de Guid.Empty? Este é apenas um problema bobo criado pelo design do .NET e realmente me incomoda quando as convenções de uma linguagem se sobrepõem. Até agora, a resposta com melhor desempenho foi usar o COM Interop porque o Framework não o trata normalmente? "Esta cadeia pode ser um GUID?" deve ser uma pergunta fácil de responder.
Contar com a exceção lançada não tem problema, até que o aplicativo entre na Internet. Nesse ponto, acabei de me preparar para um ataque de negação de serviço. Mesmo que eu não seja "atacado", sei que alguns yahoo vão enganar a URL, ou talvez meu departamento de marketing envie um link incorreto e meu aplicativo sofra um desempenho bastante pesado que PODE trazer no servidor porque não escrevi meu código para lidar com um problema que NÃO DEVE acontecer, mas todos sabemos que ACONTECERÁ.
Isso atrapalha um pouco a linha em "Exceção" - mas a linha inferior, mesmo que o problema não seja frequente, se isso acontecer várias vezes em um curto espaço de tempo para que seu aplicativo travar, atendendo às capturas de tudo, acho que lançar uma exceção é má forma.
TheRage3K
fonte
se TypeOf ctype (myvar, Object) É Guid, então .....
fonte
fonte
Com um método de extensão em C #
fonte