Как использовать обработчик событий с делегатом от дочернего класса с интерфейсом - PullRequest
0 голосов
/ 24 апреля 2020

Я провел здесь некоторые поиски и не смог получить четкого ответа на мою проблему. У меня есть несколько дочерних классов, все с 1 интерфейсом. У меня есть родительский класс, который содержит переменную, и эта переменная создается как новые экземпляры одного из этих дочерних классов в зависимости от внешних параметров. Вот некоторый код:

public interface I
{
    public delegate void ExecutionCompletedHandler(bool status);
    public event ExecutionCompletedHandler executionCompleted;
    public void Execute();
}

public class C1 : I
{
    public void Execute()
    {
        // Create background worker and execute DoStuff
    }

    public void BackgroundWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        bool status = (bool)e.Result;
        this.executionCompleted(true);
    }
}

public class C2 : I
{
    // Same setup as C1
}

public class C3 : I
{
    // Same setup as C1
}

public class MyManager
{
    public void doStuff(int val)
    {
        var compObj = null;
        // compObj is now instantiated as new instance of C1, C2 or C3 depending on val
        // ex: compObj = new C1();

        compObj.executionCompleted += new I.ExecutionCompletedHandler(executionCompletedHandler);
        compObj.Execute();
    }

    private void executionCompletedHandler(bool status)
    {
        // Do stuff with status and exit gracefully
    }
}

Это то, что я хотел бы сделать, но я знаю, что это неправильно. Я чувствую, как будто я на 90% пути туда. Это говорит о том, что переменная executeCompleted в классе C1 скрывает переменную интерфейса. Я пытался следовать различным руководствам и примерам, но не смог понять это. Спасибо!

Редактировать: я использую. NET 4.0 в Visual Studio 2010.

РЕДАКТИРОВАТЬ 2: Я смог понять это с помощью @NikProtsman ... Я преобразовал интерфейс к абстрактному классу, и в этом абстрактном классе реализована функция CompleteExecution. В этой функции я бы вызвал обработчик событий. В классах C1 / C2 / C3, когда фоновый работник завершает выполнение, я бы назвал этот метод. Работает отлично. Мы находимся в процессе обновления до VS 2019, и после этого я собираюсь сделать pu sh, чтобы это произошло быстрее! Спасибо!

1 Ответ

1 голос
/ 24 апреля 2020

Попробуйте:

В вашем интерфейсе измените Execute на:

public Task Execute();

В вашем классе C1:

//Add this line to conform to Interface
public event I.ExecutionCompleteHandler executionCompleted;

public async Task Execute()
{
    // Create background worker and execute DoStuff
    await DoStuff();
    // You'll need to supply appropriate args here
    BackgroundWorkerCompleted(this, args);
}

public void BackgroundWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    bool status = (bool)e.Result;
    //Changed this line, assumed you needed the status from the line above
    executionCompleted?.invoke(status);
}

Далее ваш MyManager должен выглядеть следующим образом :

public class MyManager
{
    public async Task doStuff(int val)
    {
        var compObj = null
        // compObj is now instantiated as new instance of C1, C2 or C3 depending on val
        compObj = new C1();

        // Subscribe to the 'executioncompleted' event in your new instance
        compObj.executionCompleted += HandleExecutionComplete;
        // Execute your code
        await compObj.Execute();
        // Unsubscribe from the event (cleaning up after yourself)
        compObj.executionCompleted -= HandleExecutionComplete;
    }

    private void HandleExecutionComplete(bool status)
    {
        // Do stuff with status and exit gracefully
    }
}

Ключевым моментом здесь является правильное назначение обработчика выполнения в вашем менеджере, а затем использование его для подписки на событие класса C1. Внутри класса C1 используйте Task для DoStuff и ждите его в Execute, который становится asyn c Task. Как только DoStuff будет выполнено, запустится задача WorkerCompleted, запустит ваш обработчик и вы отключите go

Все это может быть несколько упрощено, но это выходит за рамки этого вопроса. Идея состоит в том, как будет работать поток управления, используя asyn c вызовы с await, чтобы убедиться, что ваша программа ожидает того, что ей нужно, а затем продолжает, и как вы подписываетесь на это событие извне.

Обязательно дождитесь звонка MyManager.doStuff также и снаружи, в противном случае ожидаемые результаты не будут получены вовремя.

...