2012-10-24 9 views
11

Si consideri il seguente codice:avviso del compilatore sbagliato quando si confrontano struct su null

DateTime t = DateTime.Today; 

bool isGreater = t > null; 

Con Visual Studio 2010 (C# 4, NET 4.0), ottengo il seguente avvertimento: CS0458

avvertimento : Il risultato dell'espressione è sempre 'null' di tipo 'bool?'

Questo non è corretto; il risultato è sempre false (di tipo bool):

Ora, il DateTime struct sovraccarica il (maggiore di) Operatore >. Qualsiasi struttura non nullable (come DateTime) è implicitamente convertibile nel tipo Nullable<> corrispondente. L'espressione sopra equivale esattamente a

bool isGreater = (DateTime?)t > (DateTime?)null; 

che genera anche lo stesso avviso errato. Qui l'operatore > è l'operatore sollevato. Funziona restituendo false se HasValue di uno dei suoi due operandi è false. In caso contrario, l'operatore sollevato sarebbe procedere a scartare i due operandi alla struct sottostante, e quindi chiamare il sovraccarico di > definita da tale struct (ma questo non è necessario in questo caso in cui un operando non si HasValue).

Puoi riprodurre il bug, ed è questo bug noto? Ho frainteso qualcosa?

Questo è lo stesso per tutti i tipi di struttura (tipi non semplici come int e non tipi di enumerazione) che sovraccaricano l'operatore in questione.

(Ora, se usiamo == invece di >, tutto dovrebbe essere del tutto simile (perché DateTime sovraccarica anche l'operatore ==). Ma non è simile. Se dico

DateTime t = DateTime.Today; 

bool isEqual = t == null; 

ottengo non avvertimento ☹ a volte si vedono persone controllare accidentalmente una variabile o un parametro per nulla, non rendendosi conto che il tipo di loro variabile è una struttura (che sovraccarica == e che non è un tipo semplice come int). sarebbe meglio se hanno avuto un avvertimento .)


Aggiornamento: con il compilatore C# 6.0 (basata su Roslyn) di Visual Studio 2015, il messaggio errato con isGreater sopra si trasforma in un CS0464 con un messaggio di avviso corretto e disponibile. Inoltre, la mancanza di avviso con isEqual sopra è fissa nel compilatore di VS2015, ma solo se si compila con /features:strict.

+0

'[nulla]> null non ha senso iniziare (almeno per me). Interessante comunque, penso che dovrebbe mettere in guardia sul 'bool' che finisce sempre come' false'. – Alex

+1

Potrebbe essere utile: http://blogs.msdn.com/b/abhinaba/archive/2005/12/11/501544.aspx e http://blogs.msdn.com/b/abhinaba/archive/2005/12 /14/503533.aspx – Habib

+0

È interessante notare che 'DateTime.CompareTo (oggetto)' _specifically_ restituisce '1' quando si confronta con' null', qualunque sia il tipo di oggetto passato. – Rawling

risposta

5

Si è corretto: questo è un bug in Visual Studio. Il C# 4.0 standard (§ 7.3.7 operatori sollevata) ha questo da dire:

Per gli operatori relazionali

< > <= >= 

[...] L'operatore sollevato produce il valore false se uno o entrambi gli operandi sono nulli ...

E infatti, in MonoDevelop, si ottiene il seguente avviso invece:

Il risultato di tipo System.DateTime a confronto con null è sempre false.

+0

Ma, in questo ' > 'caso, il risultato è falso, non nullo. Il tipo del risultato è 'bool', non' bool? '. – Rawling

+0

@Rawling È vero? Suona male, dovrebbe essere sicuramente "bool?" Dato che l'operatore è sollevato. –

+0

Visual Studio sembra pensarlo, ma 'DateTime.Today> null' mi dà' false' di tipo 'bool', e il richiedente ottiene lo stesso, apparentemente. Sono d'accordo che è strano. – Rawling

1
DateTime t = DateTime.Today; 

bool isGreater = (DateTime?)t > (DateTime?)null; 

In questo scenario di cosa si tratta è t > null. Questo non sarà mai vero. Perché non può essere valutato.

In questo scenario:

bool isGreater = (DateTime?)t > (DateTime?)null; 

Stiamo valutando (DateTime?)t > (DateTime?)null;

O essenzialmente nel migliore dei casi t > null; come prima. DateTime.Ora non può mai essere maggiore di Non definito, quindi l'avviso.

+0

Accetto che sia rilevante per un avviso, ma hai letto il messaggio di avviso ** **? È il testo dell'avvertimento che disturba in modo preoccupante, non il fatto che venga emesso un avviso. (Forse a un certo punto durante lo sviluppo di tipi nullable si prevedeva che gli operatori di confronto sollevati ('>', '==', e così via) si comportassero diversamente, ma poi cambiarono idea?) –

9

Ho scoperto questo errore in modo indipendente mentre implementavo il comportamento dell'operatore sollevato in Roslyn e l'ho risolto in Roslyn prima di partire.

Spiacente di non averlo visto quando l'hai postato in ottobre. Grazie per averlo inviato a Connect! E molte scuse per l'errore; è un errore di vecchia data nell'analisi semantica dell'operatore.

Per inciso, io sarò discutendo come Roslyn ottimizza sollevato espressioni su http://ericlippert.com a fine mese (dicembre 2012), quindi se questo soggetto che si interessi, check it out:

http://ericlippert.com/2012/12/20/nullable-micro-optimizations-part-one/

+3

Non è necessario scusarsi per non aver visto ogni thread su Stack Overflow. Spero di ricordare di controllare il tuo prossimo post sugli operatori sollevati. –