IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Devinettes en C# (Réponses)

Date de publication : 23/03/2012.

Par Jon Skeet Site personnel Blog

 Jean-Michel Ormes (traduction) Site personnel Blog

 

niveau : Débutant

Voici les réponses aux devinettes en C#. J'ai inclus les questions encore une fois pour un peu plus de clarté.

       Version PDF (Miroir)   Version hors-ligne (Miroir)
Viadeo Twitter Facebook Share on Google+        



Traduction
1. Surcharge
2. Ordre ! Ordre !
3. Bête arithmétique
4. Print, print, print....
5. En apparence, tout semble aller avec le compilateur ici ...
6. Inférence type à gogo
Remerciements


Traduction

Ceci est la traduction la plus fidèle possible de l'article de Jon Skeet, ang Brainteasers C#.


1. Surcharge

Qu'est-ce qui est affiché, et pourquoi?

using System;

class Base
{
    public virtual void Foo(int x)
    {
        Console.WriteLine ("Base.Foo(int)");
    }
}

class Derived : Base
{
    public override void Foo(int x)
    {
        Console.WriteLine ("Derived.Foo(int)");
    }
    
    public void Foo(object o)
    {
        Console.WriteLine ("Derived.Foo(object)");
    }
}

class Test
{
    static void Main()
    {
        Derived d = new Derived();
        int i = 10;
        d.Foo(i);
    }
}
					
Réponse : Derived.Foo(object) est affiché - Lorsque l'on choisi une surcharge, s'il y a des méthodes compatibles déclarés dans une classe dérivée, toutes les signatures déclarées dans la classe de base sont ignorées - même si elles sont de substitution dans la même classe dérivée!


2. Ordre ! Ordre !

Qu'est-ce qui va s'afficher, pourquoi, et en êtes-vous sûr ?
   	
using System;

class Foo
{
    static Foo()
    {
        Console.WriteLine ("Foo");
    }
}

class Bar
{
    static int i = Init();
    
    static int Init()
    {
        Console.WriteLine("Bar");
        return 0;
    }
}

class Test
{
    static void Main()
    {
        Foo f = new Foo();
        Bar b = new Bar();
    }
}	
Réponse : Dans ma boîte, Bar est affiché, puis Foo. En fait, Foo contient un constructeur statique qui ne peut être exécuté tant que le point exact de la classe est initialisé n'est pas atteint. Bar n'a pas un constructeur statique, donc le CLR peut l'initialiser plus tôt. Cependant, il n'y à rien qui garantisse que Bar soit affiché. Aucun champ statique n'est référencé, donc en théorie, le CLR n'a pas à l'initialiser dans notre exemple. Tout cela est dû au flag présent dans le beforefieldinit.


3. Bête arithmétique

Les ordinateurs sont censés être bons en calcul, n'est-ce pas ? Alors pourquoi la console renvoie "False" ?
  
double d1 = 1.000001;
double d2 = 0.000001;
Console.WriteLine((d1-d2)==1.0);		
Réponse : Toutes les valeurs ici sont stockées sous forme binaire à virgule flotante. Lorsque 1.0 peut être stocké convenablement, 1.000001 est stocké ainsi : 1.0000009999999999177333620536956004798412322998046875, et 0.000001 est stocké ainsi : 0.000000999999999999999954748111825886258685613938723690807819366455078125. La différence entre ces deux valeurs ne correspond pas à 1.0, et de ce fait la différence ne peut être correctement stockée. En apprendre plus sur les binaires à virgule flotante.


4. Print, print, print....

Voici un code utilisant les fonctionnalités de méthode anonyme de C # 2. Que fait-il?
  
using System;
using System.Collections.Generic;

class Test
{
    delegate void Printer();
    
    static void Main()
    {
        List<Printer> printers = new List<Printer>();
        for (int i=0; i < 10; i++)
        {
            printers.Add(delegate { Console.WriteLine(i); });
        }
        
        foreach (Printer printer in printers)
        {
            printer();
        }
    }
} 		
Réponse : Ah, les joies des variables d'entrées. Il n'y a qu'une seule variable i ici, et sa valeur change à chaque itération de la boucle. Les méthodes anonymes récupèrent la variable elle-même plutôt que sa valeur au moment de la création - de sorte que le résultat soit imprimé dix fois!


5. En apparence, tout semble aller avec le compilateur ici ...

Est-ce que ce code pourrait compiler ? Compile t'il ? Qu'est-ce que cela signifie?
   	
using System;

class Test
{
    enum Foo { Bar, Baz };
    
    static void Main()
    {
        Foo f = 0.0;
        Console.WriteLine(f);
    }
}	
Réponse : Cela ne devrait pas compiler, mais il le fait dans les compilateurs MS à la fois pour C # 2 et 3 (et probablement 1 aussi- je n'ai pas vérifié). Il ne devrait pas compiler parce que le littéral 0 doit être implicitement convertible à la valeur par défaut de toute énumération. Ici, la valeur décimale est 0,0. Juste un petit bug du compilateur. Le but est d'afficher Bar en tant que valeur 0 de Foo.

En voici plus avec les mêmes lignes....
   
using System;

class Test
{
    enum Foo { Bar, Baz };
    
    const int One = 1;
    const int Une = 1;
    
    static void Main()
    {
        Foo f = One-Une;
        Console.WriteLine(f);
    }
}		
Réponse : Erf !! C'est pire ! Ce code ne compilera pas pour C# 2 mais le fera pour C# 3. C'est un bug connu dû à une optimisation qui s'effectue trop tôt, la collecte de constantes de 0 et le fait de penser que toute constante 0 connue puisse convertible à la valeur 0 de toute énumération. Ce bug ne sera probablement jamais corrigé car il pourrait provoquer quelques changements au sein du code, ce qui est techniquement illégal, mais fonctionne parfaitement bien. Il est fort possible que les spécifications changent, bien sûr.


6. Inférence type à gogo

J'ai d'abord vu ceci sur le blog d'Ayende (en une forme un peu plus obscure, il est vrai). Encore une fois, réfléchissez sur ce que le code va afficher et pourquoi.
   
using System;

class Test
{
    static void Main()
    {
        Foo("Hello");
    }
    
    static void Foo(object x)
    {
        Console.WriteLine("object");
    }
    
    static void Foo<T>(params T[] x)
    {
        Console.WriteLine("params T[]");
    }
}		
Réponse : params T [] est affiché. Maintenant pourquoi le compilateur choisir de créer un tableau alors qu'il n'en a pas besoin? Eh bien ... il ya deux étapes à ce sujet. Tout d'abord, en essayant de trouver les surcharges qui sont des candidats légitimes à être appelés, l'inférence type fonctionne alors que T devrait être de type System.String. Rien d'effrayant à ce jour.

Puis les surchargent essaient de travailler avec la méthode qui semble être la plus «intéressante». Si c'est un choix entre la chaîne x et l'objet params string [] x, l'ancien gagnera toujours - mais à ce stade, c'est effectivement un choix entre x et l'objet params string [] x. (Le fait que ce soit en fait une méthode générique n'est pertinent que dans une situation tie-break). Dans le but d'avoir de "meilleures conversions", la forme développée de la méthode avec le paramètre params est ensuite utilisé. Cela signifie qu'actuellement, les conversions actuelles sont prises en compte, les choix sont l'objet x ou la chaîne x - très clairement, ces derniers l'emportent.


Remerciements

Je tiens à remercier Jon Skeet pour son aimable autorisation de traduire cet article, ainsi que .... pour sa relecture attentive et ses corrections.



               Version PDF (Miroir)   Version hors-ligne (Miroir)

Valid XHTML 1.0 TransitionalValid CSS!

Copyright © 2012 Jon Skeet. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Droits de diffusion permanents accordés à Developpez LLC.