C# Позднее связывание и динамическое ключевое слово не будут работать вместе

Я пытаюсь следовать примерам из книги Pro C# 5.0 и наткнулся на пример, который я не могу заставить работать:

static void Main() {

    Assembly asm = Assembly.Load("CarLibrary");

    Type MiniVan = asm.GetType("CarLibrary.MiniVan");

    dynamic d = Activator.CreateInstance(Minivan);

    Console.WriteLine("Type of d is {0}", d.GetType()); // Type is CarLibrary.MiniVan

    MethodInfo m = MiniVan.GetMethod("TurboBoost");
    m.Invoke(d, null); // This works fine, and prints out "Turbo Boosting"

    d.TurboBoost(); // This doesn't work like the book says it should. 
                    // I get: object does not contain a definition for TurboBoost;

Вот объявление CarLibrary:

namespace CarLibrary {

    // UPDATE: I just realized that I had declared MiniVan internal
    internal MiniVan {

        public void TurboBoost() {

            Console.WriteLine("Turbo Boosting");
        }
    }
}

Таким образом, хотя MiniVan объявлен как ВНУТРЕННИЙ, с помощью Reflection я все же могу создать экземпляр MiniVan и вызвать TurboBoost(). Но если я использую ключевое слово dynamic, вызов TurboBoost () не работает. Если MiniVan объявлен как PUBLIC, оба случая работают отлично.

Может ли кто-нибудь сказать мне, все ли так, как должно быть?

1 ответ

Решение

dynamic соблюдает правила доступности, которые включают не только доступность члена, но также и то, является ли тип объекта internal, private (вложенный) и т. д. dynamic это не просто обертка вокруг отражения - это больше: это сработало бы в обычном C# отсюда.

Это означает, что такое же использование dynamic выполнено внутри CarLibrary сборка, сработало бы. Если вы хотите получить доступ к членам типа через dynamic тогда это должно быть public или как минимум: доступно в контексте вызова.

В частности, это не позволяет вам обманывать среду выполнения путем доступа public Члены internal типы, о которых вы никогда не должны были знать напрямую. Например, предположим, что тип ядра CLI реализует некоторый интерфейс:

public ISomeInterface {...}
internal SomeMicrosoftType : ISomeInterface
{
    public void FireTheMissiles() {...}
}

Сейчас; вполне может быть API, который выставляет этот объект как ISomeInterface экземпляр - так что мы могли бы законно иметь ссылку на объект этого. В нашем обычном коде мы могли бы получить доступ к членам ISomeInterface, но мы бы не смогли позвонить FireTheMissiles, Однако, если то, что вы предлагаете, сработало, то мы могли бы сделать:

ISomeInterface innocent = ...
dynamic evil = innocent;
evil.FireTheMissiles();

Да, мы можем сделать это с помощью рефлексии, но рефлексия имеет дополнительные проверки, особенно если мы не работаем с полным доверием.

Другие вопросы по тегам