Подтвердить что ты не робот

Почему я получаю эту ошибку компиляции, пытаясь вызвать базовый конструктор/метод, который принимает динамический аргумент?

Во время рефакторинга какого-то кода я столкнулся с этой странной ошибкой компиляции:

Вызов конструктора должен быть динамически отправлен, но не может быть потому, что он является частью инициализатора конструктора. Подумайте о том, как использовать динамические аргументы.

Это происходит при попытке вызвать базовые методы/конструкторы, которые принимают динамические аргументы. Например:

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

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

Он работает, если я передаю аргумент object, например:

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

Итак, я немного смущен. Почему я должен положить этот неприятный бросок - почему компилятор не может понять, что я имею в виду?

4b9b3361

Ответ 1

Цепочка конструктора должна быть определена для определенного во время компиляции - компилятор должен выбрать перегрузку, чтобы он мог создать действительный IL. В то время как обычно разрешение перегрузки (например, для вызовов методов) может быть отложено до времени выполнения, что не работает для вызовов цепочечных цепочек.

РЕДАКТИРОВАТЬ: В "нормальном" коде С# (до С# 4, в основном) все разрешения перегрузки выполняются во время компиляции. Однако, когда вызов участника включает динамическое значение, это разрешается во время выполнения. Например, рассмотрим следующее:

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);
    }
}

Компилятор не посылает прямой вызов Foo здесь - он не может, потому что в вызове Foo(d) он не знает, какую перегрузку он разрешит. Вместо этого он испускает код, который выполняет мини-компиляцию "только во времени", чтобы разрешить перегрузку с фактическим типом значения d во время выполнения.

Теперь это не работает для цепочки конструкторов, так как действительный IL должен содержать вызов к определенному конструктору базового класса. (Я не знаю, не может ли динамическая версия быть выражена в IL или она может, но результат будет непроверенным.)

Вы можете утверждать, что компилятор С# должен иметь возможность сказать, что существует только один видимый конструктор, который может быть вызван, и этот конструктор будет всегда доступен... но как только вы начнете с этой дороги, вы получите язык, который очень сложно указать. Дизайнеры С# обычно занимают более простые правила, которые иногда не так сильны, как вам бы хотелось.