Страницы

Поиск по вопросам

понедельник, 8 июля 2019 г.

Запустить метод при создании экземпляра

Есть класс A
partial class A { public event EventHandler MyHandler; public A() { }; }
partial class A { protected void H1(object sender, EventArgs e) { Something1(); }; protected void B1() { MyHandler += H1; } }
partial class A { protected void H2(object sender, EventArgs e) { Something2(); }; protected void B2() { MyHandler += H2; } }
partial class A { protected void H3(object sender, EventArgs e) { Something3(); }; protected void B3() { MyHandler += H3; } }
Мне необходимо, чтобы разделяемый класс вызывал метод B[N] в конструкторе, при этом не меняя первое определение. Поясню, у меня есть куча файлов cs, каждый из них определяет логику поведения экземпляра, подключая их и отключая - класс A ведёт себя по разному. Иногда нужно чтобы модуль подключался к событиям этого класса при его создании. Как это сделать?
Как решал проблему: Как вариант использовал атрибут
public class AutoInitialize : Attribute { }
и в методы добавлять атрибут
[AutoInitialize] public void B1() { } [AutoInitialize] public void B2() { } [AutoInitialize] public void B3() { }
а в основной конструктор вставляем текст
MethodInfo[] methods = GetType() .GetMethods() .Where(x => x.GetCustomAttribute(typeof(AutoInitialize)) != null && !x.IsStatic).ToArray(); foreach (MethodInfo method in methods) { method.Invoke(this, new object[0]); /* try { method.Invoke(this, new object[0]); } catch { } */ }


Ответ

В комментариях объяснить свою точку зрения не удалось, поэтому описываю здесь.
Я вижу решение следующим образом.
Создаем интерфейс, метод которого будет использован при инициализации.
interface IInitializer { void Initialize(IA a); // аналог методов B1, B2, B3 }
// нужен для доступа к членам класса A interface IA { event EventHandler MyHandler; } Создаем реализации.
class Initializer1 : IInitializer { public B(IA a) { a.MyHandler += (s, e) => Something1(); } }
class Initializer2 : IInitializer { ... } Вызываем метод для всех реализаций.
class A : IA { public A() { var initializers = new IInitializer[] { new Initializer1(), new Initializer2(), ... } foreach (var i in initializers) { i.Initialize(this); } } }
Насколько я понимаю, вас смущает необходимость перечислять все инициализаторы в классе A. Т.е. при создании нового инициализатора придется менять класс A. Для того, чтобы избежать этого можно воспользоваться каким-нибудь контейнером. Например, MEF

Рассмотрим пример с MEF. Сначала пометим реализации атрибутом Export
[Export(typeof(IInitializer))] class Initializer1 : IInitializer { ... }
[Export(typeof(IInitializer))] class Initializer2 : IInitializer { ... }
Потом подправим класс A
class A : IA { public A() { // Выбор каталога зависит от ваших нужд. В данном случае предполагается, что все реализации лежат в этой же сборке. using (var catalog = new AssemblyCatalog(GetType().Assembly)) using (var container = new CompositionContainer(catalog)) { var initializers = container.GetExportedValues(); foreach ... } } }
Писал без VS, так что за компилируемость не ручаюсь.

Комментариев нет:

Отправить комментарий