bool b = val; то возникнет ошибка при выполнении из-за отсутствия неявного преобразования типа int (который оказывается типом переменной val во время выполнения) в тип bool. Поэтому данная строка кода приведет к ошибке при выполнении, хотя она и будет скомпилирована безошибочно. Прежде чем оставить данный пример программы, попробуйте поэксперименти ровать с ней. В частности, измените тип переменных str и val на object, а затем попытайтесь скомпилировать программу еще раз. В итоге появятся ошибки при ком пиляции, поскольку тип object не поддерживает действия, выполняемые над обеи ми переменными, что и будет обнаружено во время компиляции. В этом, собственно, и заключается основное отличие типов object и dynamic. Несмотря на то что оба типа могут использоваться для ссылки на объект любого другого типа, над перемен ной типа object можно производить только те действия, которые поддерживаются типом object. Если же вы используете тип dynamic, то можете указать какое угодно действие, при условии что это действие поддерживается конкретным объектом, на ко торый делается ссылка во время выполнения. Для того чтобы стало понятно, насколько тип dynamic способен упростить реше ние некоторых задач, рассмотрим простой пример его применения вместе с рефлек сией. Как пояснялось в главе 17, чтобы вызвать метод для объекта класса, получаемого во время выполнения с помощью рефлексии, можно, в частности, обратиться к методу Invoke. И хотя такой способ оказывается вполне работоспособным, нужный метод намного удобнее вызвать по имени в тех случаях, когда его имя известно. Например, вполне возможна такая ситуация, когда в некоторой сборке содержится конкретный класс, поддерживающий методы, имена и действия которых заранее известны. Но по скольку эта сборка подвержена изменениям, то приходится постоянно убеждаться в том, что используется последняя ее версия. Для проверки текущей версии сборки можно, например, воспользоваться рефлексией, сконструировать объект искомого класса, а за тем вызвать методы, определенные в этом классе. Теперь эти методы можно вызвать по имени с помощью типа dynamic, а не метода Invoke, поскольку их имена известны. Разместите сначала приведенный ниже код в файле с именем MyClass.cs. Этот код будет динамически загружаться посредством рефлексии.
public class DivBy { public bool IsDivBylint a, int b) { if((a % b) == 0) return true; return false; } public bool IsEven(int a) { if((a % 2) == 0) return true; return false; }
} Затем скомпилируйте этот файл в библиотеку DLL под именем MyClass.dll. Если вы пользуетесь компилятором командной строки, введите в командной строке следующее.
csc /t:library MyClass.cs Далее составьте программу, в которой применяется библиотека MyClass.dll, как показано ниже.
// Использовать тип dynamic вместе с рефлексией. using System; using System.Reflection;
class DynRefDemo { static void Main { Assembly asm = Assembly.LoadFrom("MyClass.dll"); Type[] all = asm.GetTypes; // Найти класс DivBy. int i; for(i = 0; i < all.Length; i++) if(all[i].Name == "DivBy") break; if(i == all.Length) { Console.WriteLine("Класс DivBy не найден в сборке."); return; } Type t = all[i]; //А теперь найти используемый по умолчанию конструктор. ConstructorInfо[] ci = t.GetConstructors; int j; for(j = 0; j < ci.Length; j++) if(ci[j].GetParameters.Length == 0) break; if(j == ci.Length) { Console.WriteLine("Используемый по умолчанию конструктор не найден."); return; } // Создать объект класса DivBy динамически. dynamic obj = ci[j].Invoke (null); // Далее вызвать по имени методы для переменной obj. Это вполне допустимо, // поскольку переменная obj относится к типу dynamic, а вызовы методов // проверяются на соответствие типов во время выполнения, а не компиляции. if(obj.IsDivBy(15, 3)) Console.WriteLine("15 делится нацело на 3."); else Console.WriteLine("15 HE делится нацело на 3."); if(obj.IsEven(9)) Console.WriteLine("9 четное число."); else Console.WriteLine("9 HE четное число."); }