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

{

Name = tokens[1].Trim();

Helper.MakeInt(tokens[3].Trim(), 0, maxAge, out age);

}

public override bool Equals(object o)

{

Man m = o as Man;

return m == null ? false : name.Equals(m.name) && age.Equals(m.age);

}

public override int GetHashCode() { return (name + age).GetHashCode(); }

public string NameLast

{

get { return name.Substring (name.LastIndexOf(' ') + 1); }

}

public string NameFirst

{

get

{

int n = name.IndexOf(' ');

return name.Substring (0, (n < 0 ? name.Length : n));

}

}

}

}

Построить библиотеку можно с помощью команды Rebuild контекстного меню, вызванного над именем проекта.

Клиентское приложение

Теперь создайте новый проект обычного приложения консольного типа с именем TestManReflect. Поместите в него следующий код. Замените путь к файлу с библиотекой на тот, который соответствует вашему случаю, и выполните приложение по шагам, а затем и обычным способом.

using System;

using System.Reflection;

using System.Text.RegularExpressions;

namespace TestManReflect

{

class Test

{

static void Main()

{

Assembly a = Assembly.LoadFrom("E:/VCS/ConsoleDLL/bin/Debug/ConsoleDLL.dll");

Type man = null;

object o = null;

PropertyInfo[] props = null;

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

foreach (Type type in a.GetTypes())

{

if (type.Name == "Man")

{

man = type;

o = Activator.CreateInstance(type);

props = type.GetProperties();

Console.WriteLine ("\n\tMan Properties:\n{0}\n", line);

foreach (PropertyInfo p in props)

Console.WriteLine ("\t{0,-10}:  {1}", p.Name, p.GetValue(o, null));

Console.WriteLine (line);

}

}

Console.WriteLine ('\n');

}

}

}

Внимательно исследуйте каждую строку кода и объясняйте происходящее. Покажем, как использовать класс Regex, позволяющий создавать шаблоны поиска соответствий (регулярных выражений), для того, чтобы отобрать только те свойства исследуемого класса, которые начинаются со слова Name. Добавьте этот фрагмент в конец метода Main (перед строкой Console.WriteLine ('\n');) и проверьте его в работе.

o = Activator.CreateInstance(man, new object[]{"Alex Black", 30});

Regex r = new Regex ("^name", RegexOptions.IgnoreCase); // Find and get all naming properties

Console.WriteLine ("\n\tNaming Properties:\n{0}\n", line);

foreach (PropertyInfo p in props)

if (r.IsMatch (p.Name))

Console.WriteLine ("\t{0,-10}:  {1}", p.Name, p.GetValue(o, null));

Console.WriteLine (line);

Следующий фрагмент выявляет все методы класса и вызывает только тот, который в качестве параметра требует  массив строк. Добавьте его в конец метода Main и проверьте его в работе.

BindingFlags flags = BindingFlags.Public | BindingFlags.Instance |

BindingFlags.DeclaredOnly;

MethodInfo[] methods = man.GetMethods(flags);

Console.WriteLine ("\nOur man is: {0}\n\n\tMan methods:\n{1}\n", o, line);

MethodInfo read = null;

foreach (MethodInfo method in methods)

{

ParameterInfo[] pInfo = method.GetParameters();

Console.WriteLine (" {0,-14}:  requies  {1} parameters", method.Name, pInfo.Length);

if (pInfo.Length > 0 && pInfo[0].ParameterType.Name == "String[]")

read = method;

}

Console.WriteLine (line);

if (read != null)

{

read.Invoke (o, new object[] { new string[]{"", "Peter Pen","","25"} });

Console.WriteLine ("\nExecuting: {0}\nNow the man is: {1}\n", read.Name, o);

}

Что мы выяснили в результате проведения численного эксперимента?

¨  Механизм рефлексии позволяет выявить содержащиеся в сборке (Assembly) типы (Assembly.GetTypes()), их свойства (type.GetProperties()), методы (type.GetMethods(flags)) и параметры (method.GetParameters()).

¨  Рефлексия позволяет управлять 'чужими' объектами, а именно: динамически создавать объекты вновь выявленных типов (Activator.CreateInstance(type)), устанавливать их свойства (например, property.SetValue(object, value, null)) и вызывать методы с помощью универсального вызова Invoke. Аналогичный метод используется в технологии COM (см. COM-интерфейс IDispatch).

¨  Возможности, предоставляемые механизмом рефлексии, значительно превышают те, что дает технология COM, они стабильны, не зависят от номерков в реестре, переносятся в любое место сети вместе с объектами.

В дополнение к тому, что уже сделано, выявите все поля (type.GetFields()) класса Man и его интерфейсы (для этого сначала реализуйте два интерфейса: IComparable и ICloneable). Экспериментируйте с другими свойствами и методами классов Assembly, Activator, Type и Regex. Задействуйте, например, класс ConstructorInfo и воспользуйтесь его возможностями для выяснения параметров конструкторов. Исследуйте класс Helper, который также находится в сборке ManReflect.dll.