Ответ 1
Фундаментальный принцип "динамического" в С#: во время выполнения выполняет анализ типа выражения, как если бы тип времени выполнения был типом времени компиляции. Поэтому давайте посмотрим, что произойдет, если мы действительно это сделаем:
dynamic num0 = ((Program.Factory.Empty)container).Value;
Эта программа потерпит неудачу, потому что Empty
недоступен. dynamic
не позволит вам выполнить анализ, который был бы незаконным в первую очередь.
Однако анализатор времени выполнения реализует это и решает немного обмануть. Он спрашивает себя: "Существует ли базовый класс Пустоты, доступный?" и ответ, очевидно, да. Поэтому он решает вернуться к базовому классу и анализировать:
dynamic num0 = ((System.Object)container).Value;
Что не удается, потому что эта программа даст вам "объект не имеет члена, называемого значением". Какая ошибка вы получаете.
Динамический анализ никогда не говорит "о, вы, должно быть, имели в виду"
dynamic num0 = ((Program.IContainer)container).Value;
потому что, конечно, если это то, что вы имели в виду, то, что вы написали бы в первую очередь. Опять же, цель dynamic
заключается в том, чтобы ответить на вопрос, что произошло бы, если бы компилятор знал тип среды выполнения, а приведение в интерфейс не дает вам тип времени выполнения.
Когда вы перемещаете Empty
снаружи, тогда динамический анализатор времени выполнения делает вид, что вы написали:
dynamic num0 = ((Empty)container).Value;
А теперь Empty
доступен, а трансляция законна, поэтому вы получите ожидаемый результат.
UPDATE:
может скомпилировать этот код в сборку, ссылаться на эту сборку, и он будет работать, если пустой тип находится вне класса, который сделает его внутренним по умолчанию.
Я не могу воспроизвести описанное поведение. Попробуем небольшой пример:
public class Factory
{
public static Thing Create()
{
return new InternalThing();
}
}
public abstract class Thing {}
internal class InternalThing : Thing
{
public int Value {get; set;}
}
> csc /t:library bar.cs
class P
{
static void Main ()
{
System.Console.WriteLine(((dynamic)(Factory.Create())).Value);
}
}
> csc foo.cs /r:bar.dll
> foo
Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:
'Thing' does not contain a definition for 'Value'
И вы видите, как это работает: связующее средство времени выполнения обнаружило, что InternalThing
является внутренним для внешней сборки и поэтому недоступно в foo.exe. Поэтому он возвращается к типу публичной базы, Thing
, который доступен, но не имеет необходимого свойства.
Я не могу воспроизвести описанное вами поведение, и если вы можете воспроизвести его, вы обнаружите ошибку. Если у вас есть небольшой репортаж об ошибке, я рад передать ее моим бывшим коллегам.