Pourquoi ce code n’est-il pas inaccessible?

J’ai trouvé un cas où j’ai un code que je trouve inaccessible et qui n’est pas détecté. Aucun avertissement n’est émis ni par le compilateur ni par Visual Studio.

Considérez 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"); } } } 

De toute évidence, le programme n’imprimera pas “lol” car la condition dans l’instruction if est fausse. Je ne comprends pas pourquoi un avertissement n’est pas émis pour le code inaccessible si. Ma seule hypothèse est que cela pourrait être accessible si vous avez une situation de concurrence dans un programme multi-thread. Est-ce correct?

    L’parsing statique ne peut que faire beaucoup, et ne marquera le code que comme étant inaccessible s’il peut prouver qu’une valeur ne peut pas être modifiée. Dans votre code, ce qui se passe à l’intérieur de Bar est hors de scope du stream de méthodes et ne peut pas être statiquement raisonné. Que se passe-t-il si le constructeur de Bar lance un thread qui définit la valeur de type sur B ? Le compilateur ne peut pas le savoir car, encore une fois, les composants internes de Bar ne sont pas liés à la méthode.

    Si votre code vérifiait la valeur d’une variable locale , le compilateur pourrait savoir s’il n’y avait aucun moyen de le modifier. Mais ce n’est pas le cas ici.

    La spécification C # dit,

    La première instruction incorporée d’une instruction if est accessible si l’instruction if est accessible et que l’expression booléenne ne possède pas la valeur false.

    et, en ce qui concerne les expressions constantes ,

    Une expression constante doit être le littéral nul ou une valeur avec l’un des types suivants: sbyte, octet, short, ushort, int, uint, long, ulong, char, float, double, décimal, bool, object, ssortingng ou tout autre type d’énumération.

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

    • Littéraux (y compris le littéral null ).
    • Références aux membres const des types class et struct.
    • Références aux membres des types d’énumération.
    • Références aux parameters const ou aux variables locales
    • Sous-expressions entre parenthèses, qui sont elles-mêmes des expressions constantes.
    • Cast expressions, à condition que le type de cible soit l’un des types listés ci-dessus. expressions cochées et non vérifiées
    • Expressions de valeur par défaut
    • Le + , , prédéfini ! et opérateurs unaires.
    • Le prédéfini + , , * , / , % , << , >> , & , |, ^ , && , || , == != , < , > , <= et >= opérateurs binarys, à condition que chaque opérande soit du type indiqué ci-dessus.
    • L'opérateur conditionnel?

    Les expressions d'access aux membres ne figurent pas dans cette liste. L'expression booléenne n'est donc pas constante. Ainsi, le corps du bloc if est accessible.

    Car aucune garantie de ce type ne peut être faite à la compilation. Considérez cette classe de barre alternative

     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é à atteindre en dehors de la fonction qui est testée, même si cela peut être fait en toute sécurité.

    L’avertissement attendu n’est pas implémenté car ce n’est pas un avertissement utile à avoir.

    Dans les applications du monde réel, le compilateur est très souvent confronté à du code qu’il peut totalement prouver qu’il est inaccessible, peut-être même quelque chose d’aussi chauve que

     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 qu’il n’y a pas d’avertissement pour cela non plus. En effet, lorsque vous mettez if (false) { ... } autour d’un bloc de code, vous l’avez fait express, peut-être pour désactiver quelque chose temporairement pour une expérience. Il ne serait pas utile de vous en parler.

    Plus commun est que ce n’est pas un littéral false , c’est une constante à la compilation que le système de construction définira à true ou false selon la configuration; vous voulez que le compilateur supprime le code inaccessible dans une version, mais pas dans l’autre, et vous ne voulez pas avoir à vous plaindre.

    Plus commun encore que cela est pour les premières optimisations comme l’inlining et la propagation constante pour découvrir qu’une condition est toujours fausse; supposons que vous ayez 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); } } 

    Vous ne voudriez manifestement pas savoir qu’un côté du conditionnel à l’intérieur de Fizz () était inaccessible simplement parce qu’il n’a été appelé qu’avec l’argument 4 de ce programme .