Em um banco de dados relacional um valor nulo é usado em uma coluna quando o valor é desconhecido ou ausente. Um nulo não é uma string vazia (para tipos de dados string ou datetime), nem um valor zero (para tipos de dados numéricos). (MSDN)
Em alguns códigos que utilizam DataReader para leitura dos dados eu costumo encontrar verificações se o valor retornado da base de dados não é nulo como o código a seguir:
...
if( myDataReader["columnName"] != DBNull.Value )
{
myObject.Propriety = Convert.ToBoolean( myDataReader ["columnName"] );
}
else
{
//Faça algo
}
...
Eu particularmente acho essa forma de verificação um tanto “deselegante”, pois no momento em seja feita a leitura de alguma tabela que possua vários campos que podem retornar nulo a quantidade de “if” será grande e prejudicará a leitura do código e deixará o método extenso.
Para contornar isso, uma solução que encontrei foi com a utilização de extension methods e generics.
using System;
namespace MyNamespace
{
public static class MyExtensions
{
public static T DefaultDbNull( this Object value, object defaultValue )
{
if( value == Convert.DBNull )
return ( T )defaultValue;
return ( T )value;
}
}
}
Forma de usar:
... myObject.Propriety = myDataReader["columnName"].DefaultDbNull( string.Empty ); ...
Desta forma eliminamos uma grande quantidade de “if”, em troca de um único método de extensão que poderá ser reutilizável em todo o aplicativo que utilizar a classe de extensão.
Postado em C#, Dicas | Marcado como DBNull, Extension Methods, generics
Olá, Gabriel, tudo bem ?
Interessante este seu post. Eu, particularmente, utilizo uma outra forma de fazer isto, mas não sei se é o mesmo caso.
Pelo que percebi, você altera o conteúdo da coluna no DataReader, mas não entendi em que momento.
Eu utilizo uma condição ternária (acho que é este o termo), da seguinte forma, para preencher campos com o resultado da leitura no banco:
myObject.Property = myDataReader["ColumnName"].Value != DBNull.Value ? myDataReader["ColumnName"] : tipo_De_Dado_Corresponte.
Não sei se falei besteira, pois sou novato em .NET, mas é assim que eu faço.
Valeu!
Olá Arboni! Obrigado pelo seu feedback!
Quanto a sua implementação com condição ternária, ela faz o mesmo trabalho que a verificação utilizando “if” que demonstrei no primeiro exemplo de código, mas ela tem uma sintaxe mais compacta que o comando “if”, porem no meu ponto de vista a utilização de varias verificações ternarias acaba retirando a clareza do código e dificultando seu fácil entendimento, alem de não ser reutilizável (você vai ter que fazer essa verificação ternaria em todos os lugares).
Minha proposta com a utilização de extension methods é criar um método de fácil entendimento para quem ler o código, e ser reutilizável em qualquer lugar do projeto bastando somente adicionar a classe “MyExtensions” (ou o nome que você preferir) no projeto.
Para ter acesso a ela em qualquer parte do projeto basta remover seu namespace na definição da classe, e como ela é uma extensão de object, qualquer objeto terá esse método, da mesma forma que todo objeto tem o método ToString.
Espero ter conseguido explicar minha ideia.
Abraço.
Ola, Gabriel.
Explicou perfeitamente sua idéia. Eu até já havia entendido sua proposta, mas não havia pensado na questão de condição ternária ser um “if disfarçado”.
Eu só não entendi como deixar esta classe disponível no projeto inteiro nem a forma como você a referenciou no código onde foi utilizada.
Eu não entendi como esta classe se tornou um método de um objeto e, pelo que você comentou, se tornaria um método de qualquer objeto.
De qualquer forma, gostei da ideia e vou tentar utilizá-la.
Valeu e parabéns pelo post. Esqueci disto no comentário anterior!
Olá Arbonomi!
Para disponibilizar esse método no seu projeto basta adicionar a classe “MyExtensions” em seu projeto.
Para você entender como todos os objetos vão ter esse método de uma olhada nesse post
http://csharpbrasil.com.br/csharp/extension-methods/
Espero ter ajudado.
Qualquer duvida entre em contato.
Abraço.
Muito interessante seu post Gabriel.
Realmente é muito mais interessante vc possuir um método estendido do que ficar repetindo o código por diversos formulários.
De qualquer forma, pelo menos na minha opinião, um código grande, muito grande é melhor que seja dividido em partes.
Mesmo que as vezes utilizemos para uma vez.
Para facilitar a leitura.
Parabéns pelo post.
Ola estou aprendendo muito com esse site esta dando esse erro no meu
Error 1 The type or namespace name ‘T’ could not be found (are you missing a using directive or an assembly reference?)
nao estou conseguindo
Willian, Também estou apreendendo.
mas mudei o codigo e deu certo.
public static Object DefaultDbNull(this Object value, object defaultValue)
{
if (value == Convert.DBNull)
return defaultValue;
return value;
}
Olá está faltando um pequeno detalhe no código que impede seu perfeito funcionamento (no meu blog o mesmo esta correto, e eu não estou conseguindo editar aqui no C# Brasil), segue ele abaixo:
using System;
namespace MyNamespace
{
public static class MyExtensions
{
public static T DefaultDbNull( this object value, object defaultValue )
{
if( value == Convert.DBNull )
return ( T )defaultValue;
return ( T )value;
}
}
}
Observação: Para ter os metodos de extensão disponiveis em todo projeto basta fazer referencia ao namespace da classe de extensão onde você for usa-la:
using MyNamespace;
Ou você pode deixar a classe que contem os metodos de extensão sem namespace e ela estará disponível sem precisar fazer referência ao namepace já que ela não terá um (não acho uma boa prática).
Link para o post no meu blog http://goo.gl/qsndX
Desculpem, acabei de notar que o blog esta filtrando alguns caracteres do codigo (por medidas de segurança) por isso o codigo não fica correto. No meu blog ele esta disponivel:
http://goo.gl/qsndX