Domanda

Qualcuno può chiarire la is parola chiave C # per favore. In particolare, queste 2 domande:

Q1) linea 5; Perché questo ritorno vero?

Q2) linea 7; Perché non fa eccezione cast?

public void Test()
{
    object intArray = new int[] { -100, -200 };            

    if (intArray is uint[]) //why does this return true?
    {
        uint[] uintArray = (uint[])intArray; //why no class cast exception?

        for (int x = 0; x < uintArray.Length; x++)
        {
            Console.Out.WriteLine(uintArray[x]);
        }
    }
}

Descrizione di MSDN non chiarisce la situazione. Essa afferma che is restituirà vero se una di queste condizioni sono soddisfatte. (Http://msdn.microsoft.com/en-us/library/scekt9xw(VS.71).aspx>MDSN articolo)

expression is not null.
expression can be cast to type.

Non credo che si può fare un cast valida di int [] in uint []. Perché:

A) Questo codice non può essere compilato:

int[] signed = new int[] { -100 };
uint[] unsigned = (uint[])signed; 

B) Fare il cast nel debugger dà un errore:

(uint[])signed
"Cannot convert type 'int[]' to 'uint[]'"

E infatti, se la linea 3 è stato int [] invece di oggetto allora sarebbe mai compilazione. Il che mi porta a una domanda finale relativa al Q2.

Q3) Perché C # sollevano un errore di fusione / conversione nel debugger e compilatore, ma non in fase di esecuzione?

È stato utile?

Soluzione

C # e il CLR hanno un po 'diverse regole di conversione.

Non è possibile direttamente Cast tra int[] e uint[] in C #, perché il lingua non crede alcuna conversione è disponibile. Tuttavia, se si va via object il risultato è all'altezza del CLI. Dalla sezione CLI spec 8.7 (mi auguro - sto citando un scambio di email che ho avuto su questo tema con Eric Lippert qualche tempo fa):

  

È stato firmato e non firmato integrale primitiva   tipi possono essere assegnati a vicenda;   per esempio, int8: = uint8 è valido. Per questo   scopo, bool è considerato   compatibile con uint8 e viceversa,   che rende bool := uint8 valido e   vice versa. Ciò vale anche per   matrici di firmato e unsigned integrale   tipi primitivi delle stesse dimensioni;   per esempio, int32[] := uint32[] è valido.

(non ho controllato, ma supporre che questo tipo di conversione tipo di riferimento essendo valido è ciò che rende ritorno is vero.)

E 'un po' un peccato che ci sono sconnessioni tra il linguaggio e il motore di esecuzione sottostante, ma è praticamente inevitabile nel lungo periodo, ho il sospetto. Ci sono alcuni altri casi come questo, ma la buona notizia è che raramente sembrano causare danni significativi.

EDIT:. Come Marc cancellato la sua risposta, ho collegato alla piena posta da Eric, come descritto al C # newsgroup

Altri suggerimenti

Ora che è interessante. Ho trovato questo nello standard ECMA-335. 4.3 castclass. Si noti che:

  • Array ereditano da System.Array.

  • Se Foo può essere lanciato a Bar, poi Foo [] può essere lanciato a Bar [].

  • Ai fini del precedente nota 2, enumerazioni vengono trattati come loro tipo sottostante:. Così E1 [] può essere fusa per E2 [] se E1 e E2 condividono un tipo sottostante

È possibile lanciare int a uint, ma che si comporta come questo è molto strano. Visual Studio non riconosce nulla di tutto questo, anche l'orologio, quando il debugger è collegato mostra solo un punto di domanda '?'.

Si potrebbe desiderare di dare un'occhiata a questo , avanti veloce di circa 10 minuti e ascoltare Anders spiegare l'implementazione serie co-variant. Credo che questo sia il problema fondamentale di fondo qui.

Suggerimento:

Dichiarando intArray come "int [] intArray" piuttosto che "opporsi intArray" permetterà al compilatore di prendere il C # getto valido. A meno che non sia assolutamente necessario utilizzare l'oggetto, vorrei prendere questo approccio.

Re Q2, Q3:

In fase di runtime hai provato avvolgendo il cast in un controllato bloccare?

Da questo articolo a MSDN:

  

Per impostazione predefinita, un'espressione che   contiene solo valori costanti provoca un   errore di compilatore se l'espressione   produce un valore che è al di fuori   gamma del tipo di destinazione. Se la   espressione contiene uno o più   valori non costanti, fa il compilatore   non rileva l'overflow.

     

...

     

Per impostazione predefinita, questi non costante   espressioni non vengono controllati per   Overflow in fase di esecuzione o, e loro   non sollevare eccezioni di overflow. Il   all'esempio precedente visualizza   -2.147,483639 millions come la somma di due numeri interi positivi.

     

controllo di overflow può essere abilitato   opzioni del compilatore, ambiente   configurazione o utilizzo del controllato   parola chiave.

Come si dice, è possibile applicare il controllo di troppo pieno più a livello globale tramite un ambiente compilatore o ambiente di configurazione.

Nel tuo caso questo è probabilmente auspicabile in quanto causerà un errore di runtime per essere gettato in grado di garantire il numero senza segno probabile valido per trabocco numero con segno non si verificherà in silenzio.

[Aggiornamento] Dopo aver testato questo codice, ho trovato che l'uso di una dichiarazione di tipo di oggetto invece di int [] appare per bypassare lo sytax C # fusione di serie, indipendentemente dal fatto controllato è abilitato o meno.

Come ha detto JS, quando si utilizza oggetto, si sono tenuti dalle regole CLI e questi a quanto pare permettere che questo accada.

Re Q1:

Questo è legato a quanto sopra. In breve, perché il cast coinvolto non un'eccezione (sulla base di impostazione di overflow corrente). Se questa è una buona idea è un'altra questione.

Da MSDN :

  

Una "è" espressione restituisce true se l'espressione condizione non è nullo, e la   disponibile oggetto può essere fusa al tipo fornito senza causare un'eccezione essere   gettato.

Sto indovinando all'indietro compatablility con .NET 1: Sono ancora un po 'sfocata sui dettagli, ma ho beleive il tipo CLR di tutti gli array è semplicemente System.Array, con proprietà Type in più per cercare il tipo di elemento. 'È' probabilmente solo non ha spiegare che nel CLR v1, e ora deve mantenere tale.

Non funziona nel caso (uint[])(new int[]{}) è probabilmente dovuto al compilatore C # (non il runtime CLR) di essere in grado di fare più severe typechecking.

Inoltre, le matrici sono solo di tipo pericoloso in generale:

Animal[] tigers = new Tiger[10];
tigers[3] = new Elephant(); // ArrayTypeMismatchException

OK,

tento di prendere una pugnalata a questo.

Prima di tutto, la documentazione dice: "Controlla se un oggetto è compatibile con un dato tipo." Si dice anche che se il tipo a sinistra è "calcinabile" (è possibile convertire senza eccezioni) per il tipo sul a destra, e l'espressione restituisce non nullo, il "si" parola chiave valuterà a true.

Guardate di Jon Skeet per l'altra risposta. Ha detto che più eloquente di quanto ho potuto. Ha ragione, se una conversione è disponibile, accetta la sintassi, si potrebbe poi scrivere il proprio, ma sembrerebbe eccessivo in questa situazione.

Riferimento: http://msdn.microsoft. com / it-it / library / scekt9xw (VS.80) aspx

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top