2012-06-01 8 views
15

Ho il seguente bit di codice per impostare un parametro che verrà utilizzato in un'istruzione INSERT per impostare una colonna VARCHAR in un database SQL Server. Il mio oggetto valore (denominato ilo) ha una proprietà denominata Descrizione che viene inizializzata in String.Empty e quindi viene impostata su un valore letto da XML oppure, se quell'elemento XML è vuoto, rimane semplicemente String.Empty.L'impostazione del parametro su DBNull.Value utilizzando la sintassi ternaria genera un errore?

Quindi, quando si inserisce nel database, se la proprietà è ancora impostata su String.Empty, mi piacerebbe averlo inserire un valore nullo.

database.AddInParameter(cmd, "@description", DbType.String, 
          (ilo.Description.Equals(string.Empty)) ? 
          DBNull.Value : 
          ilo.Description); 

Quindi, in pratica quello che sto dicendo, se è uguale a ilo.Description String.Empty, impostare il parametro su DBNull.Value, altrimenti impostarlo su ilo.Description.

Questo dà il seguente errore in Visual Studio ...

Errore 141 Tipo di espressione condizionale non può essere determinato, perché non v'è alcuna conversione implicita tra 'System.DBNull' e 'stringa'

Perché?

La parte curiosa è che posso fare quanto segue senza errori, che dovrebbe essere esattamente la stessa cosa che usare la sintassi condizionale in linea come sopra!?!

if(ilo.Description.Equals(string.Empty)) 
{ 
    database.AddInParameter(cmd, "@description", DbType.String, DBNull.Value); 
} 
else 
{ 
    database.AddInParameter(cmd, "@description", DbType.String, ilo.Description); 
} 

Ho cercato altri posti, e abbiamo trovato l'uno sotto, ma in realtà non rispondere alla mia domanda.

EntLib Way to Bind "Null" Value to Parameter

Sono più interessato al perché, perché la soluzione più ovvia è quella di utilizzare solo un if else/invece della linea di sintassi (ternario)?

C'è una sorta di risposta a questo link, ma mi piacerebbe una spiegazione migliore, perché mi sembra BS che questo non funzioni; Lo definirei un bug!

http://msdn.microsoft.com/en-us/library/ty67wk28.aspx

+1

È possibile ottenere dettagli sull'operatore ternario e questo tipo di problema [in questa risposta] (http://stackoverflow.com/questions/4290203/simple-c-why-assigning-null-in-ternary-operator-fails -no-implicito-conversione) – Steve

+0

Grazie Steve. Il tuo link era quello che stavo cercando davvero. Penso che questo sia un aspetto stupido di .NET però; perché non valutano solo se i tipi di ogni possibile risultato corrispondono alla dichiarazione. Ad esempio, se si dice Object o = (someBool)? someInt32: someString; si ottiene un errore, ma quanto sarebbe facile valutare che entrambi i risultati possano essere espressi in modo implicito su un oggetto, invece di valutare se è possibile eseguire il cast di qualche stringa su alcuniInt32? Mi sembra stupido, ma immagino sia così. Grazie! – Jim

+0

Vorrei anche commentare che sono molto impressionato dalla velocità e precisione delle risposte a questo thread. Questa comunità è fantastica! Grazie a tutti! – Jim

risposta

34

Questo è un errore comune persone ricevono quando si utilizza l'operatore condizionale. Per risolvere il problema, basta lanciare uno o entrambi i risultati su un tipo di base comune.

ilo.Description.Equals(string.Empty) 
    ? (object)DBNull.Value 
    : ilo.Description 

Il problema è rivelato nel messaggio di errore che hai visto.

Tipo di espressione condizionale non può essere determinato perché non v'è alcuna conversione implicita tra 'System.DBNull' e 'stringa'

Una stringa non è un DBNull, e un DBNull non è una stringa. Pertanto, il compilatore non può determinare il tipo di espressione. Usando un cast per un tipo di base comune (in questo caso, object), si crea uno scenario in cui il compilatore può quindi determinare che anche la stringa è convertibile in oggetto, quindi il tipo dell'espressione può essere determinato come oggetto, che anche si adatta a ciò che la tua linea di codice si aspetta anche come argomento DbParameter.

+0

Il commento di Steve fornisce un collegamento con maggiori dettagli, ma la tua risposta è anche molto corretta. Mi sembra stupido doverlo fare. Credo in Java questo non succede. – Jim

1

Si ottiene l'errore di compilazione perché entrambe le parti dell'espressione ternaria devono essere dello stesso tipo.La soluzione più semplice per questa particolare situazione è quello di lanciare sia a un oggetto:

database.AddInParameter(cmd, "@description", DbType.String, 
          (ilo.Description.Equals(string.Empty)) ? 
          (object) DBNull.Value : 
          (object) ilo.Description); 
+0

Come suggerito da lazyberezovsky, è anche meglio usare null anziché DBNull.Value qui. Penso che sia necessario utilizzare DBNull.Value solo quando si legge da un datareader o da un set di dati. – Tuan

2

Anthony è davvero corretto in modo che dovrebbe ottenere la risposta corretta, però qui è un metodo di estensione, perché mi annoio ...

public static object NullCheck(this string self) 
    { 
     return (string.IsNullOrEmpty(self)) ? (object)DBNull.Value : self; 
    } 

utilizzo nello scenario:

database.AddInParameter(cmd, "@description", DbType.String, 
          ilo.Description.NullCheck()); 
+0

Roba buona. Anche se probabilmente non userò questo metodo, mi ha insegnato solo alcune cose su C# che non conoscevo prima; come non ho nemmeno notato il metodo IsNullOrEmpty su String prima. Sono solo molto abituato a Java, e sono lieto di saperne di più C#. Grazie! – Jim

+0

Nessun problema, dopo averci pensato, potrebbe essere meglio mettere il metodo di estensione sull'oggetto ParameterCollection/database stesso per fornire un wrapper che gestisca i null nel modo desiderato. – Marlon

4

Questo è quello che ho trovato in un altro thread e ha funzionato grande per me:

yourVariable ?? (object)DBNull.Value 

Spero che sia d'aiuto.