我需要开始下载一些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
}
}
我意识到我不清楚自己想做什么,我很乐意填写任何缺失的部分。
感谢您的任何建议!
答案 0 :(得分:12)
活动订阅和通知
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上发现了这个thread哪种情况向我证实这样做似乎没有错。
此外,我还对该代码运行代码分析,以确保我没有通过初始化EventHandler来破坏CA1805规则。没有引发CA1805,也没有违反任何规则。
在评论中使用我的汽车类比,我认为不会初始化事件处理程序并一直提高它会比说“当你在车里转弯时只使用你的指示器,如果有人正在观看,如果没有,请” “打扰”。你永远不知道是否有人在看,所以你不妨确保你总是这样做。
这只是我个人的偏好。如果您喜欢这样做,请随时添加!= null检查。
非常感谢您对 ctacke 的评论以及指出这一点。我从中学到了很多东西 我现在必须回到我的一些项目并更新一些代码,以确保如果没有人订阅我的事件,我的库就不会崩溃。在我的任何测试中,我都感觉很傻。
答案 1 :(得分:5)
我不确定这是否是您所追求的,但您可以使用内置的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);
或者,使用standard event pattern和EventHandler<T>
委托类型。您需要创建自己的EventArgs
类型。
答案 2 :(得分:1)
你想要一个回调。
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,即; 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);
}
}
有关如何使用Events in C#的信息。
答案 3 :(得分:0)
如果我不理解你错了。我想你应该这样试试
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
}
}
答案 4 :(得分:0)
你可以尝试这种方法
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");
}
}
public class Other
{
public Other()
{
Stuff myStuff=new Stuff();
myStuff.OnDownloadComplete+=new EventHandler(myStuff_OnDownloadComplete);
}
void myStuff_OnDownloadComplete("arguments will be passed here")
{
//Do your stuff
}
}