Estou tentando criar uma extensão genérica que usa 'TryParse' para verificar se uma seqüência de caracteres é um determinado tipo:
public static bool Is<T>(this string input)
{
T notUsed;
return T.TryParse(input, out notUsed);
}
isso não será compilado, pois não pode resolver o símbolo 'TryParse'
Pelo que entendi, 'TryParse' não faz parte de nenhuma interface.
Isso é possível?
Atualizar:
Usando as respostas abaixo, criei:
public static bool Is<T>(this string input)
{
try
{
TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(input);
}
catch
{
return false;
}
return true;
}
Funciona muito bem, mas acho que usar exceções dessa maneira não parece certo para mim.
Update2:
Modificado para passar o tipo em vez de usar genéricos:
public static bool Is(this string input, Type targetType)
{
try
{
TypeDescriptor.GetConverter(targetType).ConvertFromString(input);
return true;
}
catch
{
return false;
}
}
protected Boolean TryParse<T>(Object value, out T result) { result = default(T); var convertor = TypeDescriptor.GetConverter(typeof(T)); if (convertor == null || !convertor.IsValid(value)) { return false; } result = (T)convertor.ConvertFrom(value); return true; }
ConvertFrom(value)
método em umatry-catch
quadra para pegar as exceções.Respostas:
Você deve usar a classe TypeDescriptor :
fonte
Também precisei de um TryParse genérico recentemente. Aqui está o que eu criei;
Então é simplesmente uma questão de chamar assim:
fonte
T
do manipulador, e precisamos especificar explicitamenteT
quando o chamamos. Estou curioso, por que não pode inferirT
?SomeMethod(TryParse<int>(DollarTextbox.Text, int.TryParse))
sem criar uma variável de saída para capturar o resultadoint.TryParse
. No entanto, eu concordo com o sentimento de Nick sobre ter a função inferir o tipo.Usar try / catchs para controle de fluxo é uma política terrível. Lançar uma exceção causa atrasos no desempenho, enquanto o tempo de execução trabalha em torno da exceção. Em vez disso, valide os dados antes da conversão.
fonte
converter != null
é sempre verdadeiro, para que possa ser removido do código.Se você estiver usando o TryParse, poderá usar a reflexão e fazer o seguinte:
fonte
Type.GetType(string.Format(...))
comtype.MakeByRefType()
.Isso usa um construtor estático para cada tipo genérico, portanto, ele só precisa fazer o trabalho caro na primeira vez em que você o chama em um determinado tipo. Ele lida com todos os tipos no espaço para nome do sistema que possuem métodos TryParse. Também funciona com versões anuláveis de cada uma delas (que são estruturas), exceto para enumerações.
fonte
Que tal algo como isso?
http://madskristensen.net/post/Universal-data-type-checker.aspx ( arquivo )
Isso pode ser convertido para um método genérico com bastante facilidade.
fonte
catch { }
. No entanto, nesse caso, não há alternativa, porque o .NETBaseNumberConverter
lança aException
classe base em caso de erro de conversão. Isso é muito lamentável. De fato, ainda existem alguns lugares onde esse tipo de base é lançado. Espero que a Microsoft os corrija em uma versão futura do framework.Você não pode fazer isso em tipos gerais.
O que você pode fazer é criar uma interface ITryParsable e usá-la para tipos personalizados que implementam essa interface.
Acho que você pretende usar isso com tipos básicos como
int
eDateTime
. Você não pode alterar esses tipos para implementar novas interfaces.fonte
dynamic
palavra - chave, porque não funcionará na digitação estática. Você pode criar seu próprio objeto dinâmico que pode lidar com isso, mas não é o padrão.Inspirado na solução postada aqui por Charlie Brown, criei um TryParse genérico usando reflexão que, opcionalmente, gera o valor analisado:
Pode ser chamado assim:
Atualização:
Também graças à solução do YotaXP de que realmente gosto, criei uma versão que não usa métodos de extensão, mas ainda possui um singleton, minimizando a necessidade de refletir:
Chame assim:
fonte
Um pouco tarde para a festa, mas aqui está o que eu criei. Sem exceções, reflexão única (por tipo).
A classe extra é necessária porque métodos de extensão não são permitidos dentro de classes genéricas. Isso permite o uso simples, como mostrado abaixo, e apenas atinge a reflexão na primeira vez que um tipo é usado.
fonte
Aqui está outra opção.
Eu escrevi uma classe que facilita o registro de qualquer número de
TryParse
manipuladores. Isso me permite fazer isso:Sou
42
impresso no console.A turma é:
fonte
Quando eu queria fazer quase exatamente isso, tive que implementá-lo da maneira mais difícil, considerando a reflexão. Dado
T
, refletir sobretypeof(T)
e olhar para umaTryParse
ouParse
método, invocando-se que você o encontrou.fonte
Esta é a minha tentativa. Eu fiz isso como um "exercício". Tentei torná-lo tão semelhante ao uso como os existentes " Convert.ToX () " -ones etc. Mas este é o método de extensão:
fonte
TypeConverter.ConvertFrom()
é que a classe de origem precisa fornecer a conversão de tipo, o que geralmente significa que você não pode suportar a conversão para tipos personalizados.Como você disse,
TryParse
não faz parte de uma interface. Também não é membro de nenhuma classe base, pois é realmentestatic
estatic
funções não podem servirtual
. Portanto, o compilador não tem como garantir queT
realmente tenha um membro chamadoTryParse
, portanto isso não funciona.Como o @Mark disse, você pode criar sua própria interface e usar tipos personalizados, mas não tem sorte com os tipos internos.
fonte
fonte
Esta é uma questão de 'restrições genéricas'. Como você não possui uma interface específica, fica paralisado, a menos que siga as sugestões da resposta anterior.
Para documentação sobre isso, verifique o seguinte link:
http://msdn.microsoft.com/en-us/library/ms379564(VS.80).aspx
Ele mostra como usar essas restrições e deve fornecer mais algumas dicas.
fonte
Emprestado de http://blogs.msdn.com/b/davidebb/archive/2009/10/23/using-c-dynamic-to-call-static-members.aspx
ao seguir esta referência: Como chamar o método estático no C # 4.0 com tipo dinâmico?
E use-o da seguinte maneira:
fonte
Eu consegui algo que funciona assim
Aqui está o meu código
O StaticMembersDynamicWrapper é adaptado do artigo de David Ebbo (estava lançando uma AmbiguousMatchException)
fonte
fonte
Com o
TypeDescriptor
uso da classe deTryParse
maneira relacionada:fonte
Usando as informações acima, é isso que desenvolvi. É possível converter o objeto diretamente, caso contrário, ele será convertido em uma string e chamará o método TryParse para o tipo de objeto desejado.
Eu cache os métodos em um dicionário, pois cada um deles é encontrado para reduzir a carga de busca do método.
É possível testar se o objeto pode ser convertido diretamente no tipo de destino, o que reduziria ainda mais a parte de conversão da string. Mas vou deixar isso de fora por enquanto.
fonte
Coloquei um monte de idéias aqui e acabei com uma solução muito curta.
Este é um método de extensão em uma string
Fiz isso com a mesma pegada dos métodos TryParse nos tipos numéricos
'' '
fonte
T.TryParse ... por quê?
Não vejo nenhum benefício em ter essa
TryParse
função genérica . Existem muitas estratégias diferentes para analisar e converter dados entre tipos diferentes, com possível comportamento conflitante. Como essa função poderia saber qual estratégia escolher de maneira livre de contexto?Convert.ChangeType
. Essa API é personalizável em tempo de execução. Sua função requer comportamento padrão ou permite personalização?fonte
Uma versão para obter descendentes do XDocument.
fonte