Eu quero fazer algo assim:
myYear = record.GetValueOrNull<int?>("myYear"),
Observe o tipo anulável como o parâmetro genérico.
Como a GetValueOrNull
função pode retornar nula, minha primeira tentativa foi a seguinte:
public static T GetValueOrNull<T>(this DbDataRecord reader, string columnName)
where T : class
{
object columnValue = reader[columnName];
if (!(columnValue is DBNull))
{
return (T)columnValue;
}
return null;
}
Mas o erro que estou recebendo agora é:
O tipo 'int?' deve ser um tipo de referência para usá-lo como parâmetro 'T' no tipo ou método genérico
Certo! Nullable<int>
é um struct
! Então, tentei alterar a restrição de classe para uma struct
restrição (e como efeito colateral não pode mais retornar null
):
public static T GetValueOrNull<T>(this DbDataRecord reader, string columnName)
where T : struct
Agora a tarefa:
myYear = record.GetValueOrNull<int?>("myYear");
Dá o seguinte erro:
O tipo 'int?' deve ser um tipo de valor não anulável para usá-lo como parâmetro 'T' no tipo ou método genérico
É possível especificar um tipo anulável como um parâmetro genérico?
IDataRecord
a partir deDbDataRecord
..Respostas:
Altere o tipo de retorno para Nullable e chame o método com o parâmetro não nulo
fonte
Apenas use-o assim:
fonte
GetValueOrDefault
para esclarecer que ele retorna emdefault(T)
vez denull
. Como alternativa, você pode emitir uma exceção seT
não for anulável.Faça duas coisas no código original - remova a
where
restrição e altere a últimareturn
dereturn null
parareturn default(T)
. Dessa forma, você pode retornar o tipo que desejar.A propósito, você pode evitar o uso
is
alterando suaif
declaração paraif (columnValue != DBNull.Value)
.fonte
return default
é suficiente (você não precisa do(T)
, o compilador o inferirá do tipo de retorno de assinatura).Isenção de responsabilidade: Esta resposta funciona, mas destina-se apenas a fins educacionais. :) A solução de James Jones é provavelmente a melhor aqui e certamente a que eu escolheria.
A
dynamic
palavra-chave do C # 4.0 torna isso ainda mais fácil, se menos seguro:Agora você não precisa da dica explícita de tipo no RHS:
Na verdade, você nem precisa disso!
value
agora será um int, ou uma string ou qualquer tipo que foi retornado do banco de dados.O único problema é que isso não impede que você use tipos não anuláveis no LHS; nesse caso, você receberá uma exceção de tempo de execução bastante desagradável, como:
Tal como acontece com todo o código que usa
dynamic
: caveat coder.fonte
Só tinha que fazer algo incrível semelhante a isso. Meu código:
fonte
Eu acho que você deseja lidar com tipos de referência e tipos de estrutura. Eu o uso para converter seqüências de caracteres de elemento XML em um tipo mais digitado. Você pode remover o nullAlternative com reflexão. O provedor de formato é lidar com a cultura dependente '.' ou ',' separador, por exemplo, decimais ou ints e duplos. Isso pode funcionar:
Você pode usá-lo assim:
fonte
Isso pode ser um fio morto, mas eu costumo usar o seguinte:
fonte
Acabei de encontrar o mesmo problema.
... = reader["myYear"] as int?;
funciona e está limpo.Funciona com qualquer tipo sem problemas. Se o resultado for DBNull, ele retornará nulo quando a conversão falhar.
fonte
int v=reader["myYear"]??-1;
ou algum outro padrão em vez de-1
. No entanto, isso pode trazer problemas se o valor forDBNull
...Eu sei que isso é antigo, mas aqui está outra solução:
Agora, você não se importa se
T
foi o valor ou o tipo de referência. Somente se a função retornar true, você terá um valor razoável no banco de dados. Uso:Essa abordagem é muito semelhante à
int.TryParse("123", out MyInt);
fonte
Múltiplas restrições genéricas não podem ser combinadas de maneira OR (menos restritivas), apenas de maneira AND (mais restritivas). Significando que um método não pode lidar com os dois cenários. As restrições genéricas também não podem ser usadas para criar uma assinatura exclusiva para o método, portanto, você deve usar 2 nomes de métodos separados.
No entanto, você pode usar as restrições genéricas para garantir que os métodos sejam usados corretamente.
No meu caso, eu queria especificamente que o nulo fosse retornado e nunca o valor padrão de qualquer tipo de valor possível. GetValueOrDefault = incorreto. GetValueOrNull = bom.
Usei as palavras "Nulo" e "Nulo" para distinguir entre tipos de referência e tipos de valor. E aqui está um exemplo de alguns métodos de extensão que escrevi que complementam o método FirstOrDefault na classe System.Linq.Enumerable.
fonte
A maneira mais curta:
retornar
0
paraint
enull
paraint?
fonte