Создание метода в другом классе вызывает событие в вызове класса, когда это будет сделано? - PullRequest
1 голос
/ 01 июня 2011

Мне нужно начать загрузку некоторого html, поэтому я вызываю void GetHTML в другом классе.Когда это будет сделано, я хочу передать событие, которое оно должно вызвать в вызывающем классе.Как я мог это сделать?

Так что это выглядело бы примерно так:

public class Stuff
{
    public void GetHTML(string url, event to raise here)
    {
       //Do stuff then raise event
    }
}
public class Other
{
    public Other()
    {
        Stuff stuff = new Stuff();
        stuff.GetHTML(someUrl, somehow sending info that HTML_Done should be called);
    }
    void HTML_Done(string result, Event e)
    {
         //Do stuff with the result since it's done
    }
}

Я понимаю, что не совсем ясно с тем, что я хочу сделать, я был бы радзаполните недостающие части.

Спасибо за любые предложения!

Ответы [ 5 ]

12 голосов
/ 01 июня 2011

Подписка на событие и уведомление

public class Stuff
{
    // Public Event to allow other classes to subscribe to.
    public event EventHandler GetHtmlDone = delegate { };

    public void GetHTML(string url)
    {
        //Do stuff

        // Raise Event, which triggers all method subscribed to it!
        this.GetHtmlDone(this, new EventArgs());
    }
}

public class Other
{
    public Other()
    {
        Stuff stuff = new Stuff();

        // Subscribe to the event.
        stuff.GetHtmlDone += new EventHandler(OnGetHtmlDone);

        // Execute
        stuff.GetHTML("someUrl");
    }

    void OnGetHtmlDone(object sender, EventArgs e)
    {
        //Do stuff with the result since it's done
    }
}

Использование этого шаблона позволяет гораздо большему числу подписчиков.

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

У вас есть подписчики или нет, без разницы с классом Stuff.

Класс Stuff долженне знать о подписчике, он должен просто вызвать событие, которое он выставляет для подписки.

РЕДАКТИРОВАТЬ
Как ctacke правильно указано в комментариях, поднимаясобытие, использующее this.GetHtmlDone(this, new EventArgs());, вызовет исключение, если никто не подписался.
Я изменил свой код выше, чтобы обеспечить безопасное создание события всегда при инициализации моего обработчика событий.
Как я всегда его использую (Я уверен, что это всегда хорошая практика - всегда инициализировать то, что вы используете.

Я мог бы добавить нулевую проверку на обработчик событий, но, по моему личному мнению, я не согласен с тем, что нужнобыть ответственнымПодвижность класса stuff.Я чувствую, что событие всегда должно быть инициировано, поскольку это «ответственный» поступок.

Я нашел этот поток на SO, который как бы подтвердил мне, что он не кажется неправильнымсделайте так.

Кроме того, я также запускаю анализ кода для этого кода, чтобы убедиться, что я не нарушаю правило CA1805, инициализируя EventHandler.CA1805 не был поднят, и никакие правила не были нарушены.

Используя мою автомобильную аналогию из комментариев, я считаю, что не инициализировать обработчик событий и не поднимать его все время было бы то же самое, что сказать "При повороте угла в вашем".Автомобиль использует ваш индикатор, только если кто-то наблюдает, а если нет, не беспокойтесь ».Вы никогда не знаете, наблюдает ли кто-либо, поэтому вы также можете быть уверены, что всегда делаете это.

Это просто мое личное предпочтение.Кто-нибудь еще, пожалуйста, всегда добавляйте проверку! = Null, если вы предпочитаете это делать.

Большое спасибо за комментарии ctacke и за указание на это.Я многому научился из этого.
Мне придется вернуться к некоторым из моих проектов сейчас и обновить некоторый код, чтобы убедиться, что мои библиотеки не выходят из строя, если никто не подписывается на мои события.Я чувствую себя довольно глупо, никогда не замечая этого ни в одном из моих тестов.

5 голосов
/ 01 июня 2011

Я не уверен, что это то, что вам нужно, но вы можете использовать встроенный Action тип делегата:

public class Stuff
{
  public void GetHTML(string url, Action<string, Event> callback)
  {
     //Do stuff 

     //raise event
     callback("result here", new Event());       
  }
}

stuff.GetHTML(someUrl, HTML_Done);

В качестве альтернативы, используйте стандартный шаблон событий и тип делегата EventHandler<T>.Вам нужно будет создать свой собственный тип EventArgs.

1 голос
/ 01 июня 2011

Вы хотите перезвонить.

public class Stuff
{
    public void GetHTML(string url, Action callback)
    {
       // Do stuff

       // signal we're done 
       callback();
    }
}

public class Other
{
    public Other()
    {
        Stuff stuff = new Stuff();

        // using a lambda callback
        stuff.GetHTML(someUrl, ()=> Console.WriteLine("Done!") );
        // passing a function directly
        stuff.GetHTML(someUrl, MyCallback);
    }

    public void MyCallback() 
    {
        Console.WriteLine("Done!");
    }
}

Если вы хотите передать аргументы, определите Действие соответствующим образом, т.е. Action<string>, и тогда обратный вызов становится callback("some string")

Другой вариант - использование событий. Похоже, это было то, к чему вы стремились, когда задавали вопрос. Я бы не советовал, вариант обратного вызова лучше IMO. Хотя, для дальнейшего использования, именно так вы и будете использовать Событие в этих обстоятельствах.

public delegate void DoneEventHandler(object sender, string result);

public class Stuff
{
    public event DoneEventHandler DoneEvent = delegate {}; // avoid null check later

    public void GetHtml(string url)
    {
        // do stuff
        DoneEvent(this, "result");
    }
}

public class Other
{
    public void SomeMethod()
    {
        Stuff stuff = new Stuff();
        stuff.DoneEvent += OnDone;
        stuff.GetHtml(someUrl)
    }

    public void OnDone(objects sender, string result)
    {
        Console.WriteLine(result);
    }
}

Информация о том, как использовать События в C # .

0 голосов
/ 01 июня 2011


Вы можете попробовать этот подход


public class Stuff
{
     public delegate void DownloadComplete("you can pass whatever info you like here");
     public event DownloadComplete OnDownloadComplete;
     public void GetHtml(string UrlToDownload)
     {
         //Download the data here
         //After data download complete
         if(OnDownloadComplete)
            OnDownloadComplete("arguments to be passed");
     }</p>

<p>}
public class Other
{
     public Other()
     {
        Stuff myStuff=new Stuff();
        myStuff.OnDownloadComplete+=new EventHandler(myStuff_OnDownloadComplete);
     }</p>

<pre><code> void myStuff_OnDownloadComplete("arguments will be passed here")
 {
    //Do your stuff
 }

}

0 голосов
/ 01 июня 2011

Если я не понял вас неправильно. Я думаю, вы должны попробовать этот способ

public class Stuff 
{
     public void GetHTML(string url, event to raise here)
     {
        //Do stuff  and instead of raising event here
     }
 } 
public class Other
 {
     public Other()
     {
         Stuff stuff = new Stuff();
         stuff.GetHTML(someUrl, somehow sending info that HTML_Done should be called);
         //Raise event here once that method is finished
     }
     void HTML_Done(string result, Event e)
     {
          //Do stuff with the result since it's done
     }
 } 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...