web-dev-qa-db-fra.com

mot-clé non vérifié en C #

Peut-être que je suis dans les bases, mais j'étudie toujours cette chose en C # à l'école. Je comprends que si j’ajoute 1 à la valeur maximale d’Integer, laquelle est de 32 bits, le résultat sera négatif. J'ai lu que C # propose des mots clés cochés et non cochés pour gérer les débordements. Le mot clé coché est quelque chose que j'ai trouvé utile, mais qu'en est-il du mot clé non coché? Je ne trouve vraiment pas d'utilisation utile pour le bloc non contrôlé. Y a-t-il? Comment les deux approches suivantes diffèrent-elles l'une de l'autre?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Practice_6
{
    class Program
    {
        static void Main(string[] args)
        {
            int value = Int32.MaxValue;
            value++;
            //Approach 1 to make a decision
            if (value > Int32.MaxValue) {
                //Do something
            }
            value = Int32.MaxValue;
            //Approach 2 to make a decision
            unchecked {
                value++;
                //Do something
            }
            //What's the difference between these two approaches to handle overflow?
    }
}
26
Jere_Sumell

MISE À JOUR: Cette question était le sujet de mon blog en avril 2015 ; merci pour la question intéressante!


Votre première question est:

Le mot clé checked est utile, mais qu'en est-il du mot clé unchecked? Je ne peux vraiment pas trouver un usage pour cela. Y a-t-il? 

L'équipe de conception de C # n'a pas l'habitude d'ajouter des fonctionnalités inutilisables pour le langage. (À l'exception notable de l'opérateur unaire plus, l'opérateur le plus inutile du monde.)

Le mot clé non coché a deux cas d'utilisation principaux.

Tout d'abord, l'arithmétique de nombre entier constant est toujours vérifiée par défaut}. Cela peut être irritant. Supposons, par exemple, que vous ayez du code interop et que vous souhaitiez créer une constante pour HRESULT E_FAIL:

const int E_FAIL = 0x80004005;

C'est une erreur parce que ce nombre est trop grand pour tenir dans une int. Mais vous pourriez ne pas vouloir utiliser un uint. Vous pourriez bien penser que je vais juste dire

const int E_FAIL = (int)0x80004005;

Mais cela est également illégal car l'arithmétique constante y compris les conversions est toujours cochée par défaut.

Ce que vous devez faire est de désactiver l’arithmétique constante vérifiée via

const int E_FAIL = unchecked((int)0x80004005);

Deuxièmement, l'arithmétique par défaut pour les mathématiques entières non constantes en C # n'est pas cochée, car elle est plus rapide et c'est ce que font beaucoup d'autres langages similaires. Cependant, C # vous permet de modifier l'arithmétique cochée par défaut pour les mathématiques entières non constantes via un indicateur de compilation. Si vous l'avez déjà fait et que vous devez l'éteindre à nouveau temporairement, vous devez utiliser la syntaxe du bloc ou de l'expression unchecked.

Un troisième cas d'utilisation consiste à utiliser le bloc non contrôlé comme une forme de code auto-documenté, en disant: "Je suis conscient que l'opération que je fais ici risque de déborder, et ça me convient." Par exemple, je vais souvent écrire quelque chose comme:

int GetHashCode()
{
    unchecked 
    {
        int fooCode = this.foo == null ? 0 : this.foo.GetHashCode();
        int barCode = this.bar == null ? 0 : this.bar.GetHashCode();
        return fooCode + 17 * barCode;
    }
}

Le mot "non coché" souligne pour le lecteur que nous nous attendons à ce que la multiplication et l'ajout de codes de hachage puissent déborder, et que c'est OK.

Votre deuxième question est:

Quelle est la différence entre ces deux approches pour gérer les débordements?

Bonne question. 

Si, dans votre contexte coché, vous voulez dire: Je m'attends à ce que l'arithmétique soit toujours à l'intérieur des limites; si ce n'est pas le cas, mon programme a un bogue grave et doit être terminé avant de faire plus de mal au monde alors vous ne devriez pas faire de vérification de débordement du tout, car il n'y a pas de débordement. Toute exception devrait mettre fin au programme. le contexte vérifié permet simplement au moteur d'exécution de vérifier l'exactitude de votre code.

Si dans votre contexte coché, vous voulez dire Je demande à l'arithmétique de rester dans les limites, mais j'ai obtenu ces données auprès d'une source digne de confiance et je suis trop paresseux pour vérifier les plages , alors vous devriez capturer l'exception. Cependant, la meilleure pratique serait de vérifier les plages et de donner une erreur plus significative si les données sont en dehors des limites, plutôt que de laisser le runtime signaler le problème et émettre une exception de dépassement de capacité. Je recommanderais vivement de vérifier les plages plutôt que de prendre une exception. ne soyez pas paresseux.

38
Eric Lippert

Je ne suis pas tout à fait sûr des conséquences de checked et unchecked sur les performances. En théorie, unchecked devrait être plus performant et c'est le contexte par défaut. À moins que vous ne respectiez les limites des types entiers pour un type d'algorithme/logique métier, etc., utiliser checked est rarement nécessaire/utile/lisible.

Comme je l'ai dit, unchecked est le contexte par défaut, pourquoi avez-vous besoin d'un mot clé unchecked? Une chose pourrait être d'expliquer le type de contexte dans lequel les contextes checked sont très utilisés. L'autre consiste à utiliser le contexte unchecked à l'intérieur du contexte checked:

checked {
    int a = 5 + 1231;

    unchecked {
        a += 221;
    }
}

Votre question pourrait être pourquoi le contexte par défaut est décoché. Je suppose que c'est un choix de conception par Microsoft.

Leur différence est que le contexte checked vérifie s'il y a un dépassement de capacité pour chaque opération arithmétique et déclenche une exception en cas de dépassement de capacité.

5
mostruash

Le code correctement écrit ne devrait pas dépendre du fait qu'un projet est compilé avec ou non coché ou non. Code dans lequel un comportement arithmétique enveloppant non attendu pourrait constituer un risque pour la sécurité ou la stabilité du système doit être effectué dans un contexte checked. Le code reposant sur le comportement arithmétique du wrapping doit être créé dans un contexte unchecked. Le code à usage général dans lequel les débordements arithmétiques ne devraient pas se produire, mais auraient des conséquences limitées si tel était le cas, devrait être compilé à l'aide du paramètre au niveau du projet. Le paramètre de niveau de projet peut ensuite être défini sur coché ou désélectionné comme un compromis entre la vitesse d'exécution et le recouvrement des erreurs en temps opportun.

Si aucun débordement inattendu ne se produit, le code sera exécuté plus rapidement en mode non contrôlé. Cependant, si certains calculs donnent des valeurs erronées et que la raison pour laquelle la vérification est dépassée n'est pas claire, la recompilation avec la vérification du dépassement de capacité activée peut être utile. Le code fonctionnera plus lentement, mais s'interrompt lors du premier calcul erroné. Basculer le projet en mode vérifié à cette fin ne sera toutefois possible que si les parties du projet qui reposent sur un comportement arithmétique d'habillage sont exécutées dans un contexte explicite unchecked. Sinon, le changement de mode au niveau du projet interrompt simplement le programme.

4
supercat

À partir de MSDN, la raison de l’utilisation non cochée serait la suivante: 

Étant donné que la vérification du dépassement de capacité prend du temps, l'utilisation de code non contrôlé dans des situations où il n'y a pas de risque de dépassement de capacité peut améliorer les performances. Toutefois, si le débordement est une possibilité, un environnement vérifié doit être utilisé.

2
Mike Beeler

Changez vos codes pour:

  int value = int.MaxValue;
  unchecked
  {
    value++;
  }
  Console.WriteLine(value);
  value = int.MaxValue;
  checked
  {
    value++; // this will raise OverflowException
  }

et vous verrez la différence.

0
Setyo N