Esta pergunta surge ocasionalmente, mas não vi uma resposta satisfatória.
Um padrão típico é (a linha é um DataRow ):
if (row["value"] != DBNull.Value)
{
someObject.Member = row["value"];
}
Minha primeira pergunta é qual é mais eficiente (eu inverti a condição):
row["value"] == DBNull.Value; // Or
row["value"] is DBNull; // Or
row["value"].GetType() == typeof(DBNull) // Or... any suggestions?
este indica que .GetType () deve ser mais rápido, mas talvez o compilador conheça alguns truques que eu não conheço?
Segunda pergunta, vale a pena armazenar em cache o valor da linha ["value"] ou o compilador otimiza o indexador de qualquer maneira?
Por exemplo:
object valueHolder;
if (DBNull.Value == (valueHolder = row["value"])) {}
Notas:
- a linha ["valor"] existe.
- Eu não sei o índice da coluna (daí a pesquisa do nome da coluna).
- Estou perguntando especificamente sobre a verificação de DBNull e depois a atribuição (não sobre otimização prematura etc.).
Comparei alguns cenários (tempo em segundos, 10.000.000 de tentativas):
row["value"] == DBNull.Value: 00:00:01.5478995
row["value"] is DBNull: 00:00:01.6306578
row["value"].GetType() == typeof(DBNull): 00:00:02.0138757
Object.ReferenceEquals tem o mesmo desempenho que "=="
O resultado mais interessante? Se você não corresponder o nome da coluna por maiúsculas e minúsculas (por exemplo, "Valor" em vez de "valor", levará aproximadamente dez vezes mais (para uma sequência de caracteres):
row["Value"] == DBNull.Value: 00:00:12.2792374
A moral da história parece ser que, se você não puder procurar uma coluna por seu índice, verifique se o nome da coluna que você alimenta no indexador corresponde exatamente ao nome da DataColumn.
O armazenamento em cache do valor também parece ser quase duas vezes mais rápido:
No Caching: 00:00:03.0996622
With Caching: 00:00:01.5659920
Portanto, o método mais eficiente parece ser:
object temp;
string variable;
if (DBNull.Value != (temp = row["value"]))
{
variable = temp.ToString();
}
IDataRecord
extensões.