Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Основы C#.doc
Скачиваний:
3
Добавлен:
01.04.2025
Размер:
609 Кб
Скачать
☆

Основы c#. Урок 70. Использование атрибута Flags для перечисления 2

Одна из часто встрчающихся задач для перечисления с атрибутом Flags - это выяснение, присутствует ли некое значение перечисления в соотвествующей переменной. Например

Вот пример такого кода:

// Объявление перечисления.

[Flags()]

public enum MilitaryType

{

Marine = 1,

Land = 2,

Cosmic = 4,

MarineAndLand = Marine | Land

}

class Program

{

static void Main(string[] args)

{

MilitaryType type = MilitaryType.MarineAndLand;

// Содержится ли в переменной значение MilitaryType.Marine?

if ((type & MilitaryType.Marine) == MilitaryType.Marine)

{

Console.WriteLine("Marine");

}

else {

Console.WriteLine("Isn't marine");

}

// Содержится ли в переменной значение MilitaryType.Cosmic?

if ((type & MilitaryType.Marine) == MilitaryType.Cosmic)

{

Console.WriteLine("Cosmic");

}

else

{

Console.WriteLine("Isn't cosmic");

}

// Содержится ли в переменной значение MilitaryType.MarineAndLand?

if ((type & MilitaryType.MarineAndLand) == MilitaryType.MarineAndLand)

{

Console.WriteLine("MarineAndLand");

}

else

{

Console.WriteLine("Isn't marine or land");

}

}

}

Как вы видите, мы тут используем побитовое И. Для данного фрагмента на экране выведется два положительных ответа (для первой и последней проверки) и один отрицательный (для второй проверки).

Основы c#. Урок 71. Nullable типы

Как известно, value-типы (к ним относятся, например, int, byte и другие) не могут принимать значение null. Что, в общем-то, вполне естественно. Но иногда такая потребность возникает. Например, при работе с базами данных - в столбце таблицы могут хранится значения целого типа и, кроме того, могут допускаться неопределенные значения (NULL). В .NET 2.0 для этого появилась такая возможность - а именно так называемые nullable-типы. Они могут принимать, кроме собственно значений соотвествующего типа, значение null.

Вот пример объявления переменной такого типа и ее использования:

Nullable<int> n;

n = null;

Синтаксис тут простой - мы мы в угловых скобках указываем нужный тип (int в нашем случае).

Для объявления nullable типов, кроме указанного синтаксиса, можно использовать и упрощенный:

int? n;

С точки зрения реализации все nullable-типы являются экземплярами структуры System.Nullable.

Основы c#. Урок 72. Reflection - динамическое создание кода

Иногда нам требуется динамически создать некий код. Естественно, что этот код у нас будет храниться в некоторой сборке. При этом сама созданная динамически сборка может существовать только в памяти или же может быть сохраненной на диск в виде файла. Сейчас мы посмотрим, как это можно сделать.

Для начала небольшое замечание по порядку создания соответствующих объектов. Сначала мы должны сгенерировать сборку, затем на основании этой сборки - модуль, потом на основании этого модуля - тип (например, класс), потом на основании этого типа (класса) - его члены (конструкторы, методы и т. п.). И, уже в самом конце, мы создаем непосредственно сгенерированный на предыдущих шагах тип.

Вот пример такого кода:

// Создание имени сборки.

AssemblyName an = new AssemblyName("MyAssembly");

an.Version = new Version("1.0.0.0");

// Создание сборки.

AssemblyBuilder ab;

ab = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Save);

// Создание модуля в сборке.

ModuleBuilder mb = ab.DefineDynamicModule("MyModule", "My.dll");

// Создание типа в сборке.

TypeBuilder tb = mb.DefineType("MyClass", TypeAttributes.Public);

// Создание конструктора без параметров.

ConstructorBuilder cb0 = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, null);

// Добавление кода для конструктора.

ILGenerator il0 = cb0.GetILGenerator();

il0.Emit(OpCodes.Ret);

// Создание конструктора с параметром типа string.

ConstructorBuilder cb = tb.DefineConstructor(MethodAttributes.Public,

CallingConventions.Standard, new Type[] { typeof(string)});

// Добавление кода для конструктора.

ILGenerator il = cb.GetILGenerator();

il.EmitWriteLine("Constructor");

il.Emit(OpCodes.Ret);

// Непосредственное создание типа.

tb.CreateType();

// Сохранение типа в файл.

ab.Save("qqq.dll");

Приведенный код при запуске создаст на жестком диске файл qqq.dll, в котором будет класс с 2-я конструкторами, причем второй конструктор будет при вызове выводить строчку "Constructor".

Несколько пояснений по коду.

Первое. Очень часто при создании типов и членов этих типов надо указать их атрибуты (модификаторы доступа типа public и т. п.). Это мы делаем через перечисления TypeAttributes и MethodAttributes, которое содержит соотвествующие значения (Public, например). Несколько необходимых значений из этих перечислений можно соединить через побитовое "или".

Второе. Метод Emit класса ILGenerator в качестве параметра принимает перечисление OpCodes, которое фактически содержит инструкции на языке IL - языке, который является аналогом для .NET обычного ассемблера. Это означает, что его инструкции не столь очевидны для реального программирования - именно поэтому в качестве примера таких IL-инструкций и была приведена самая простая из них - а именно выход из функции (OpCodes.Ret).