35 votes

Pourquoi ne "int[] est uint[] == true" en C#

Quelqu'un peut-il préciser le C# is mot-clé s'il vous plaît. En particulier ces 2 questions:

Q1) ligne 5; Pourquoi ce retour vrai?

Q2), ligne 7; Pourquoi pas un casting d'exception?

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]);
        }
    }
}

MSDN description ne permet pas de clarifier la situation. Il déclare qu' is retournera true si l'une de ces conditions sont remplies. (http://msdn.microsoft.com/en-us/library/scekt9xw(SV.71).aspx>MDSN l'Article)

l'expression n'est pas nulle.
l'expression peut être converti en type.

Je ne crois pas que vous pouvez faire un valide en fonte de type int[] dans uint[]. Parce que:

A) Ce code ne compile pas:

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

B) de Faire la distribution dans le débogueur donne une erreur:

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

Bien sûr, si la ligne 3 a été int[] à la place de l'objet, alors il ne serait jamais compiler. Ce qui m'amène à une dernière question par rapport à T2.

Q3) Pourquoi est-ce que C# élever un cast/erreur de conversion dans le débogueur et le compilateur, mais pas au moment de l'exécution?

36voto

Jon Skeet Points 692016

C# et le CLR ont quelque peu différente des règles de conversion.

Vous ne pouvez pas directement exprimés entre int[] et uint[] en C# parce que la langue ne crois pas que la conversion est disponible. Cependant, si vous passez par object le résultat est à la CLI. À partir de la CLI spec section 8.7 (je l'espère - je cite un échange de mail que j'ai eu sur ce sujet avec Eric Lippert il y a un moment):

Signés et non signés intégrale primitive les types peuvent être affectés les uns aux autres; par exemple, int8 := uint8 est valide. Pour ce but, bool doit être considéré comme compatible avec uint8 , et vice-versa, ce qui rend bool := uint8 valide, et vice-versa. Ceci est également vrai pour des tableaux d'entiers signés et non signés intégrale les types primitifs de la même taille; par exemple, int32[] := uint32[] est valide.

(Je n'ai pas vérifié, mais je suppose que ce genre de référence conversion de type de validité est ce qui fait is retour vrai.)

C'est un peu regrettable qu'il n'existe pas de liens entre la langue et le sous-jacent moteur d'exécution, mais c'est à peu près inévitable sur le long terme, je pense. Il y a quelques cas de ce genre, mais la bonne nouvelle, c'est qu'ils semblent rarement causer de dommage significatif.

EDIT: Comme Marc supprimé de sa réponse, je suis lié à la messagerie complet de Eric, comme affiché sur le C# de groupes de discussion.

4voto

John Leidegren Points 21951

Maintenant, c'est intéressant. J'ai trouvé ça dans l'ECMA-335 standard. 4.3 castclass. Notez que:

  • Les tableaux hériter de Système.Tableau.

  • Si Foo peut être jeté à la Barre, puis Foo[] peut être jeté à la Barre[].

  • Aux fins de la note 2 ci-dessus, les énumérations sont traités comme un type sous-jacent: donc E1[] peuvent être exprimées à l'E2[] si E1 et E2 part d'un type sous-jacent.

Vous pouvez le convertir en int uint, mais qu'il se comporte comme cela est très étrange. Visual Studio ne reconnaît pas cela, même le regarder, lorsque le débogueur est attaché montre juste un point d'interrogation '?'.

Vous pourriez voulez prendre un coup d'oeil à ce, avance rapide 10 minutes et à l'écoute Anders expliquer la co-tableau de variantes de mise en œuvre. Je pense que c'est fondamentalement la question sous-jacente ici.

1voto

Ash Points 31541

Suggestion:

Déclarant intArray comme "int [] intArray" plutôt que sur "l'objet intArray" permettra au compilateur de ramasser les invalides C# exprimés. Sauf si vous devez absolument utiliser l'objet, j'aimerais prendre cette approche.

Re T2,T3:

Au moment de l'exécution avez-vous essayé d'emballer la fonte dans un vérifiée bloc?

À partir de cet article MSDN à l'adresse:

Par défaut, une expression qui ne contient que des valeurs de constante provoque une erreur de compilateur si l'expression produit une valeur qui est en dehors de la plage du type de destination. Si l' l'expression contient un ou plusieurs non-valeurs constantes, le compilateur ne pas de détecter le dépassement de capacité.

...

Par défaut, ces non-constant les expressions ne sont pas vérifiés débordement au moment de l'exécution, et ils ne pas soulever des exceptions de dépassement. L' exemple précédent affiche -2,147,483,639 comme la somme de deux entiers positifs.

Vérification de dépassement peut être activé par les options du compilateur, de l'environnement configuration ou d'utilisation de l'objet mot-clé.

Comme il est dit, vous pouvez appliquer la vérification de dépassement de plus à l'échelle mondiale par l'intermédiaire d'un compilateur ou le paramètre de l'environnement config.

Dans votre cas, c'est probablement souhaitable, car il va provoquer une erreur d'exécution pour être jeté à assurer le probable invalide nombre non signé à signé nombre de débordement ne se produira pas en silence.

[Mise à jour] Après avoir testé ce code, j'ai trouvé que l'utilisation d'une déclaration de type de l'objet au lieu de int [] s'affiche à contourner la norme C# casting sytax, indépendamment de savoir si la vérification est activée ou non.

Que JS a dit, lorsque vous utilisez un objet, vous êtes lié par la CLI de règles et de ces apparemment permettre que cela se produise.

Re T1:

Ceci est lié à la ci-dessus. En bref, parce que les acteurs impliqués, il ne jette pas une exception (basées sur l'état actuel de dépassement de réglage). Si c'est une bonne idée, c'est une autre question.

À partir de MSDN:

Un "est" l'expression renvoie la valeur true si la condition de l'expression est non nulle, et la condition d'objet peut être jeté à la condition de type sans provoquer une exception jetés.

0voto

Simon Buchan Points 6245

Je devine en arrière compatablility avec .NET 1: je suis encore un peu floue sur les détails, mais je crois que le type CLR de tous les tableaux est tout simplement le Système.Tableau, avec des propriétés de Type pour la recherche de l'élément de type. 'est' probablement juste de ne pas tenir compte de cela dans le CLR v1, et maintenant, doit maintenir que.

Il ne travaillant pas dans l' (uint[])(new int[]{}) de cas est probablement due au fait que le compilateur C# (pas le common language runtime, runtime) être en mesure de faire plus strictes de vérification de type.

Aussi, les tableaux sont juste type dangereux en général:

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

0voto

Chris Points 3290

OK,

J'ai tenter de prendre un coup de couteau à présent.

Tout d'abord, la documentation dit, "Vérifie si un objet est compatible avec un type donné.", Il dit aussi que SI le type de gauche est "béton" (vous pouvez convertir sans exception) pour le type sur le droit, et l'expression a la valeur non-nulle, la "est un" mot clé donnera true.

Regarder Jon Skeet pour l'autre réponse. Dit-il avec plus d'éloquence que je le pouvais. Il a raison, si une conversion est disponible, il acceptera votre syntaxe, vous pouvez ensuite écrire votre propre, mais il semblerait exagéré dans cette situation.

Référence: http://msdn.microsoft.com/en-us/library/scekt9xw(SV.80).aspx

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X