Рефлексия. Рефлексия пользовательских типов. Клиентское приложение, страница 3

Следующий фрагмент создает новую сборку (assembly) в памяти, затем в эту сборку помещается создаваемый на лету класс MyClass. Внутрь класса помещается код, эмитируемый с помощью методов множества строительных классов: AssemblyBuilder, ModuleBuilder, TypeBuilder, MethodBuilder, а также класса ILGenerator. Его метод Emit позволяет генерировать коды языка C#. Завершает строительство метод CreateType, имеющийся в классе Type.

public class MyGen

{

public Type myType;

public MyGen()

{

AppDomain domain = AppDomain.CurrentDomain;

AssemblyName assName = new AssemblyName ("MyAssembly");

AssemblyBuilder ass = domain.DefineDynamicAssembly (assName, AssemblyBuilderAccess.Run);

ModuleBuilder module = ass.DefineDynamicModule ("MyModule");

TypeBuilder type = module.DefineType("MyClass", TypeAttributes.Public);

MethodBuilder method = type.DefineMethod("Hello", MethodAttributes.Public, null, null);

ILGenerator il = method.GetILGenerator();

string line = new string('\u2500', 40);

il.EmitWriteLine("\n" + line + "\n\tThis is MyClass speaking\n\t.NET is cool!\n" + line);

il.Emit(OpCodes.Ret);

myType = type.CreateType();

}

}

Вставьте определение класса MyGen внутрь класса Test. В метод Main класса Test добавим код, который пользуется услугами генератора кодов.

Console.WriteLine("\n\nCreating MyGen to generate a new type and method in memory...");

MyGen gen = new MyGen();

Console.WriteLine("Retrieving dynamically generated type...");

Type myType = gen.myType;

if (myType != null)

{

Console.WriteLine("Instantiating the new type...");

object o = Activator.CreateInstance(myType);

Console.WriteLine("Retrieving the type's HelloWorld method...");

MethodInfo method = myType.GetMethod("Hello");

if (method != null)

{

Console.WriteLine("Invoking dynamically created Hello method...");

method.Invoke(o, null);

}

else

Console.WriteLine("Could not locate Hello method");

}

else

Console.WriteLine("Could not access Type");

Рефлексия пользовательских типов

Пространство имен System.Reflection содержит интерфейсы и классы, которые позволяют исследовать .NET-сборки (Assemblies), то есть EXE или DLL-файлы, содержащие управляемый код. Механизм рефлексии позволяет выявить содержащиеся в сборке типы, их поля, методы и свойства. Кроме того, рефлексия позволяет динамически создавать объекты этих типов, устанавливать их свойства, вызывать их методы (с помощью универсального вызова Invoke) и, таким образом управлять объектами произвольным способом.

Покажем, как работает механизм рефлексии на примере класса Man.

¨  Создайте проект типа Class Library с именем ManReflect и поместите в него код, следующий ниже.

¨  Постройте библиотеку ManReflect.dll.

¨  Запомните ее адрес. Мы обратимся к ней из другого проекта и исследуем свойства и методы класса Man с помощью механизма рефлексии.

namespace ManReflect

{

public class Helper

{

public static int AskInt (string prompt, int min, int max)

{

int res = 0;

for (bool ok = false; !ok; )

{

Console.Write (prompt);

ok = MakeInt (Console.ReadLine(), min, max, out res);

}

return res;

}

public static bool MakeInt (string s, int min, int max, out int res)

{

res = 0;

try

{

res = int.Parse (s);

if (res < min || max < res)

{

Console.WriteLine ("Value must be in ({0}, {1})", min, max);

return false;

}

}

catch

{

Console.WriteLine ("It is not valid integer");

return false;

}

return true;

}

}

public class Man

{

protected string name;

protected int age;

private static int maxName = 15, maxAge = 200;

public string Name

{

get { return name; }

set

{

int i = value.IndexOf('\n');

if (i < 0)

i = value.Length;

if (i > maxName)

value = value.Remove(maxName, value.Length-maxName);

else if (i < 1)

value = "N/A";

name = value;

}

}

public int Age

{

get { return age; }

set { Helper.MakeInt (value.ToString(), 0, maxAge, out age); }

}

public static int MaxName

{

get { return maxName; }

set { Helper.MakeInt (value.ToString(), 30, 255, out maxName); }

}

public static int MaxAge

{

get { return maxAge; }

set { Helper.MakeInt(value.ToString(), 30, 100, out maxAge); }

}

public Man() : this("N/A", 0) { }

public Man(string n, int a)

{

Name = n;

Helper.MakeInt(a.ToString(), 0, maxAge, out age);

}

public Man (Man m)

{

name = m.name;

age  = m.age;

}

~Man() { name.Remove(0, name.Length); }

public virtual void In()

{

Console.Write("\tName: ");

Name = Console.ReadLine();

age = Helper.AskInt ("Age: ", 0, maxAge);

}

public override string ToString()

{

return name.PadRight(maxName) + "; Age: " + age;

}

public virtual void Read (string[] tokens)