46 votes

Pourquoi est-ce que j'obtiens cette erreur de compilation en essayant d'appeler un constructeur/méthode de base qui prend un argument dynamique ?

En remaniant du code, je suis tombé sur cette étrange erreur de compilation :

L'appel au constructeur doit être distribué dynamiquement, mais ne peut l'être car il fait partie d'un initialisateur de constructeur. Envisagez le casting des arguments dynamiques.

Il semble se produire lorsqu'on essaie d'appeler des méthodes/constructeurs de base qui prennent des arguments dynamiques. Par exemple :

class ClassA
{
    public ClassA(dynamic test)
    {
        Console.WriteLine("ClassA");
    }
}

class ClassB : ClassA
{
    public ClassB(dynamic test)
        : base(test)
    {
        Console.WriteLine("ClassB");
    }
}

Cela fonctionne si je transforme l'argument en object así:

public ClassB(dynamic test)
    : base((object)test)

Donc, je suis un peu confus. Pourquoi faut-il que je mette ce méchant cast - pourquoi le compilateur ne peut-il pas comprendre ce que je veux dire ?

44voto

Jon Skeet Points 692016

La chaîne de constructeurs doit être déterminée avec certitude au moment de la compilation - le compilateur doit choisir une surcharge pour pouvoir créer une IL valide. Alors que normalement la résolution des surcharges (par exemple pour les appels de méthode) peut être différée jusqu'au moment de l'exécution, cela ne fonctionne pas pour les appels de constructeurs chaînés.

EDIT : Dans du code C# "normal" (avant C# 4, en gros), tous La résolution des surcharges est effectuée au moment de la compilation. Cependant, lorsqu'une invocation de membre implique une valeur dynamique, celle-ci est résolue au moment de l'exécution. Prenons l'exemple suivant :

using System;

class Program
{
    static void Foo(int x)
    {
        Console.WriteLine("int!");
    }

    static void Foo(string x)
    {
        Console.WriteLine("string!");
    }

    static void Main(string[] args)  
    {
        dynamic d = 10;
        Foo(d);
    }
}

Le compilateur n'émet pas un appel direct à Foo ici - il ne peut pas, parce que dans l'appel Foo(d) il ne sait pas à quelle surcharge il doit se résoudre. Au lieu de cela, il émet du code qui fait une sorte de mini-compilation "juste à temps" pour résoudre la surcharge avec la méthode réel de la valeur de d au moment de l'exécution.

Cela ne fonctionne pas pour le chaînage de constructeurs, car une IL valide doit contenir un appel à un constructeur de classe de base spécifique. (Je ne sais pas si la version dynamique ne peut même pas être exprimée sur en IL, ou si elle le peut, mais le résultat serait invérifiable).

On pourrait argumenter que le compilateur C# devrait être capable de dire qu'il n'y a en fait qu'un seul constructeur visible qui puede sera appelé, et ce constructeur sera toujours être disponible... mais une fois qu'on s'engage dans cette voie, on se retrouve avec une langue qui est muy compliqué à spécifier. Les concepteurs de C# adoptent généralement la position d'avoir des règles plus simples qui, parfois, ne sont pas aussi puissantes que vous le souhaiteriez.

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