49 votes

Pourquoi ce code n'est-il pas accessible?

J'ai trouvé un cas où j'ai un code que je crois être inaccessible et n'est pas détecté. Aucun avertissement n'est émis ni par le compilateur, ni par Visual Studio.

Considérer ce code:

enum Foo { A, B, C }
class Bar { public Foo type; }

static class Program
{
    private static void Main()
    {
        var bar = new Bar { type = Foo.A };

        if (bar.type == Foo.B)
        {
            Console.WriteLine("lol");
        }
    }
}

Évidemment, le programme ne s'imprime pas "lol" parce que la condition de l'instruction if est faux. Je ne comprends pas pourquoi un avertissement n'est pas délivré pour le code inaccessible si. Ma seule hypothèse est que cela pourrait potentiellement être accessible si vous avez une condition de concurrence dans un programme multi-threadé. Est-ce correct?

133voto

Avner Shahar-Kashtan Points 5550

L'analyse statique ne peut pas tout faire, et il ne fera que marquer le code comme inaccessible si l'on peut prouver qu'une valeur ne peut pas être changé. Dans votre code, ce qui se passe à l'intérieur d' Bar est en dehors du champ d'application de la méthode des flux et ne peut pas être statique motivé sur. Que faire si Bars'constructeur lance un thread qui définit la valeur de type de retour à l' B? Le compilateur ne peut pas savoir à ce sujet, parce que, encore une fois, le fonctionnement interne de l' Bar ne sont pas limités à la méthode.

Si votre code a été la vérification de la valeur d'un local variable, le compilateur pourrait savoir si il n'y avait aucun moyen de la changer. Mais ce n'est pas le cas ici.

27voto

Rawling Points 21932

La spécification C# dit,

La première incorporé déclaration d'une instruction if est accessible si la si la déclaration est accessible et l'expression booléenne n'a pas la valeur de la constante false.

et, concernant les expressions constantes,

Une expression constante doit être le littéral null ou une valeur avec l'un des types suivants: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, un objet, une chaîne ou tout type d'énumération.

Seules les constructions suivantes sont autorisées dans des expressions constantes:

  • Les littéraux (y compris l' null littérale).
  • Les références à const membres de la classe et de la structure des types.
  • Les références aux membres de l'énumération des types.
  • Les références à const paramètres ou des variables locales
  • Entre parenthèses sous-expressions, qui sont eux-mêmes des expressions constantes.
  • Fonte d'expressions, à condition que le type de cible est l'un des types énumérés ci-dessus. activée et désactivée expressions
  • Expressions de valeur par défaut
  • Les prédéfinis +, , !, et ~ des opérateurs unaires.
  • Les prédéfinis +, , *, /, %, <<, >>, &, |, ^, &&, ||, ==, !=, <, >, <=, et >= des opérateurs binaires, à condition que chaque opérande est d'un type énuméré ci-dessus.
  • L' ?: opérateur conditionnel.

L'accès des membres des expressions ne sont pas dans cette liste, si l'expression booléenne est pas constante. Ainsi, le corps du si le bloc est accessible.

9voto

Ivan Anatolievich Points 204

Parce qu'aucune telle garantie ne peut être faite au moment de la compilation. Considérez cette classe alternative de Bar

 class Bar
{
   Random random = new Random();
   Array Foos = Enum.GetValues(typeof(Foo));

    private Foo _type;
    public Foo type
    {
        get { return _type; }
        set
        {
            _type = (Foo)Foos.GetValue(random.Next(3));
        }
    }
}
 

Veuillez noter que "accessible" est défini au niveau de la fonction. Il n'est pas autorisé d'atteindre en dehors de la fonction qui est testée même lorsque cela est sûr.

2voto

Zack Points 44583

L'avertissement que vous attendiez n'est pas mis en œuvre parce que ce n'est pas un avertissement utile d'avoir.

Dans les applications réelles, le compilateur est très souvent confronté avec le code qu'il peut tout à fait prouver est inaccessible, peut-être même quelque chose d'aussi éhonté comme

static class Program
{
    private static void Main()
    {
        if (false)
        {
            Console.WriteLine("lol");
        }
    }
}

Je n'ai pas de compilateur C# sur cet ordinateur, mais je parie que vous il n'y a pas d'avertissement pour que, soit. C'est parce que, quand vous mettez en if (false) { ... } autour d'un bloc de code, vous n'avez que sur le but, peut-être pour désactiver quelque chose temporairement pour une expérience. Vous harcelant sur il ne serait pas utile.

La plus courante est que ce n'est pas un littéral false, c'est une constante de compilation que la construction du système est défini sur true ou false en fonction de la configuration, vous voulez le compilateur pour supprimer le code inaccessible en construire un mais pas l'autre, et vous ne voulez pas les plaintes de toute façon.

Même plus que cela, c'est pour le début des optimisations comme l'in-lining et de la constante de propagation de découvrir qu'une condition est toujours fausse; supposons que vous avez quelque chose comme

static class Program
{
    private static void Fizz(int i)
    {
        if (i % 3 == 0) {
            Console.WriteLine("fizz");
        } else {
            Console.WriteLine(i);
        }
    }

    private static void Main()
    {
        Fizz(4);
    }
}

De toute évidence, vous ne voulez pas obtenir a dit que d'un côté de la conditionnelle à l'intérieur de Fizz() a été inaccessible juste parce qu'il a été appelé seulement avec l'argument 4 dans ce programme.

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