Это тпример написан на вопрос с форумов MSDN. Итак, стоит задача, написать класс, в который можно подгружать методы из внешних сборок и вызывать их по мере необходимости.
Чтобы задача была интересная, давайте добавлю требование, чтобы вызов методов мог осуществляться в режиме Singlecall (при каждом вызове метода объект создается заново) и в режиме Singleton (при первом вызове объект создается, все последующие вызовы идут к этому же экземпляру).
Начну с классов, которые буду вызывать. Создав решение, я добавил в него две dll:
В первой сделал заготовку класса для вызова в режиме Singleton:
Во второй, для вызова в режиме Singlecall:
Хорошо, теперь, приведу код, который будет использоваться для вызова:
Метод для добавления метода к классу, принимает псевдоним, путь к dll, полное имя класса, имя метода и тип вызова true - Singleton. Метод для вызова, принимает только псевдоним и параметры, если они необходимы. Т.к. вызываемый метод будет возвращать значение, мы еще и указываем, какого оно будет типа (в моем примере int).
Собственно, начинаем писать класс Executor. Для начала, определим класс, для хранения информации о методах:
В классе Executor, объявим поле и напишем конструктор:
Напишем метод для добавления методов:
Ну и метод для вызова:
Как видно, в зависимости от значения свойства IsSingleton у нас происходит "ленивая" инициализация свойства Object или объект создается каждый раз.
Запускаем программу:
Напомню, что первые три вызова идут к Singleton-у, в котором происходит инкримент поля, а два последних значения получаются суммированием. Кстати, если изменить тип вызова первого метода на Singlecall:
То вывод будет отличаться, т.к. при инкрименте, каждый раз будет создаваться новый объект:
Все.
Чтобы задача была интересная, давайте добавлю требование, чтобы вызов методов мог осуществляться в режиме Singlecall (при каждом вызове метода объект создается заново) и в режиме Singleton (при первом вызове объект создается, все последующие вызовы идут к этому же экземпляру).
Начну с классов, которые буду вызывать. Создав решение, я добавил в него две dll:
В первой сделал заготовку класса для вызова в режиме Singleton:
namespace ClassLibrary1 { public class Class1 { int a = 0; public int IncAndReturn() { a++; return a; } } }
Во второй, для вызова в режиме Singlecall:
namespace ClassLibrary2 { public class Class1 { public int Sum(int a, int b) { return a + b; } } }
Хорошо, теперь, приведу код, который будет использоваться для вызова:
static void Main(string[] args) { Executor executor = new Executor(); executor.AddMethod("First_Singleton", "classlibrary1.dll", "ClassLibrary1.Class1", "IncAndReturn", true); executor.AddMethod("Second_Singlecall", "classlibrary2.dll", "ClassLibrary2.Class1", "Sum", false); Console.WriteLine(executor.Execute<int>("First_Singleton")); Console.WriteLine(executor.Execute<int>("First_Singleton")); Console.WriteLine(executor.Execute<int>("First_Singleton")); Console.WriteLine(executor.Execute<int>("Second_Singlecall", 2, 4)); Console.WriteLine(executor.Execute<int>("Second_Singlecall", 3, 1)); Console.ReadKey(); }
Метод для добавления метода к классу, принимает псевдоним, путь к dll, полное имя класса, имя метода и тип вызова true - Singleton. Метод для вызова, принимает только псевдоним и параметры, если они необходимы. Т.к. вызываемый метод будет возвращать значение, мы еще и указываем, какого оно будет типа (в моем примере int).
Собственно, начинаем писать класс Executor. Для начала, определим класс, для хранения информации о методах:
class MethodWrapper { public MethodInfo Method { get; set; } public object Object { get; set; } public ConstructorInfo Constructor { get; set; } public bool IsSingleton { get; set; } }
В классе Executor, объявим поле и напишем конструктор:
Dictionary<string, MethodWrapper> _methods = null; public Executor() { _methods = new Dictionary<string, MethodWrapper>(); }
Напишем метод для добавления методов:
public void AddMethod(string p_methodAlias, string p_dllPath, string p_classFullName, string p_methodName, bool p_isSingleton) { Assembly a = Assembly.LoadFrom(p_dllPath); if (a == null) { throw new Exception("Ошибка загрузки dll"); } Type t = a.GetType(p_classFullName); if (t == null) { throw new Exception("Ошибка извлечения класса"); } MethodInfo mi = t.GetMethod(p_methodName); if (mi == null) { throw new Exception("Ошибка извлечения метода"); } ConstructorInfo ci = t.GetConstructor(Type.EmptyTypes); if (ci == null) { throw new Exception("Ошибка извлечения конструктора по умолчанию"); } MethodWrapper wrapper = new MethodWrapper() { Constructor = ci, IsSingleton = p_isSingleton, Method = mi }; _methods.Add(p_methodAlias, wrapper); }
Ну и метод для вызова:
public T Execute(string p_methodAlias, params object[] p_params) { MethodWrapper wrapper = _methods[p_methodAlias]; object o = null; if (wrapper.IsSingleton) { if (wrapper.Object == null) { wrapper.Object = wrapper.Constructor.Invoke(new object[0]); } o = wrapper.Object; } else { o = wrapper.Constructor.Invoke(new object[0]); } return (T)wrapper.Method.Invoke(o, p_params); }
Как видно, в зависимости от значения свойства IsSingleton у нас происходит "ленивая" инициализация свойства Object или объект создается каждый раз.
Запускаем программу:
Напомню, что первые три вызова идут к Singleton-у, в котором происходит инкримент поля, а два последних значения получаются суммированием. Кстати, если изменить тип вызова первого метода на Singlecall:
executor.AddMethod("First_Singleton", "classlibrary1.dll", "ClassLibrary1.Class1", "IncAndReturn", false);
То вывод будет отличаться, т.к. при инкрименте, каждый раз будет создаваться новый объект:
Все.
Комментариев нет:
Отправить комментарий