31 votes

La substitution de méthode et les paramètres optionnels

Est-ce que quelqu'un pourrait expliquer comment ce code produit la sortie suivante?

using System;

namespace ConsoleApplication1
{
    class Test
    {
        public override string ToString() { return "ToString override"; }
        public string ToString(string optional = "")
          { return String.Format("ToString with optional parameter {0}", optional); }
    }

    class Test2
    {
        public new string ToString() { return "ToString new"; }
        public string ToString(string optional = "")
          { return String.Format("ToString with optional parameter {0}", optional); }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Test one = new Test();
            Test2 two = new Test2();
            Console.WriteLine(one);
            Console.WriteLine(one.ToString());
            Console.WriteLine(one.ToString("foo"));
            Console.WriteLine("--");
            Console.WriteLine(two);
            Console.WriteLine(two.ToString());
            Console.WriteLine(two.ToString("bar"));
            Console.ReadKey();
        }
    }
}

ToString override

ToString with optional parameter

ToString with optional parameter foo

--

ConsoleApplication1.Test2

ToString new

ToString with optional parameter bar

49voto

Jon Skeet Points 692016

D'accord, comme il y a un intérêt général, voici une version rapide :

Console.WriteLine(one)

Cela utilisera la surcharge WriteLine(object), qui à son tour exécutera la méthode virtuelle object.ToString(), substituée dans One - d'où la sortie de ToString override

Console.WriteLine(one.ToString())

Ceci examinera One et verra quelles méthodes ont été déclarées de manière nouvelle - en excluant les substitutions. Il y a exactement une telle méthode qui est applicable - celle avec le paramètre optionnel. Ainsi, celle-ci est exécutée, en utilisant la valeur par défaut, ce qui conduit à la sortie de ToString avec paramètre optionnel.

Console.WriteLine(one.ToString("foo"))

Encore une fois, mais cette fois le compilateur n'a pas besoin d'utiliser la valeur par défaut, d'où ToString avec paramètre optionnel foo

Console.WriteLine(two)

Encore une fois, cela appellera la méthode virtuelle object.ToString() de WriteLine(object). La méthode n'a pas été substituée, donc l'implémentation par défaut renvoyant le nom du type est utilisée, conduisant à la sortie de ConsoleApplication1.Test2.

Console.WriteLine(two.ToString())

Le compilateur examine toutes les méthodes déclarées dans Two qui ne substituent pas de méthodes virtuelles. Dans ce cas, il y a deux telles méthodes - celle sans paramètre et celle avec le paramètre optionnel. La méthode sans paramètre est incluse car elle est nouvelle plutôt que de substituer une méthode de la classe de base.

La méthode sans paramètre est considérée comme un candidat "meilleur" car le compilateur préfère appeler une méthode qui ne nécessite pas de remplir des paramètres optionnels. Ainsi, la sortie est ToString new

Console.WriteLine(two.ToString("bar"))

Encore une fois, le compilateur examine toutes les méthodes déclarées dans Two qui ne substituent pas de méthodes virtuelles. Dans ce cas, il y a deux telles méthodes - mais la méthode sans paramètre n'est pas applicable, ne laissant que celle avec le paramètre optionnel. Le compilateur n'a pas besoin d'utiliser la valeur par défaut du paramètre optionnel ici, car il a déjà un argument... donc la sortie est ToString avec paramètre optionnel bar

Pour en savoir plus, consultez les spécifications du langage C# - ou pour une solution intermédiaire, consultez mon article sur la surcharge.

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