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();
Да, мы можем сделать это с помощью рефлексии, но рефлексия имеет дополнительные проверки, особенно если мы не работаем с полным доверием.