我尝试在我的windows c#表单中使用this预先制作的C#tftp服务器应用程序。在作者服务器示例中,它运行良好,他使用控制台应用程序。当我尝试将他的控制台示例移植到我的表单应用程序时,它不起作用(没有错误,只是没有连接),我相信我的问题在"使用"语句:
using (var server = new TftpServer())
{
server.OnReadRequest += new TftpServerEventHandler(server_OnReadRequest);
server.OnWriteRequest += new TftpServerEventHandler(server_OnWriteRequest);
server.Start();
Console.Read();
}
不确定我是否理解正确,但我相信Console.Read()
会阻止应用退出。如果是这种情况,我将如何使用表单应用程序实现等效项。我无法绕过"使用"。对不起,我是c#的新手。
答案 0 :(得分:5)
Windows窗体将始终保持打开状态,直到用户明确关闭它们为止。它们总是有一个线程读取消息队列以供用户输入,因此它们不会以无限制的控制台应用程序的相同方式退出。在Windows窗体中,我们不得不担心多线程和并发性,而不是在控制台应用程序中。它主要是自然而然的,但并非总是如此。
正因为如此,在用户请求之前,您无法真正使用等同于Console.Read()
来暂停执行using
处理。如果你这样做了,你的表单就会显得没有反应。
但是,你很幸运! C#中的using
块只不过是用于记住在完成对象后调用IDisposable.Dispose()
的语法糖。因此,在Forms项目中与此类似,只需将server
对象存储在类范围的字段中,然后调用server.Dispose()
,例如,Button.Click
事件。当然,这只是一个例子。如果感觉更合适,您也可以在Form.Closing
上执行此操作。
高级别,你想做这样的事情:
TftpServer server;
中声明一个字段。Load
事件以及server
在构造函数中运行所需的任何内容。server
活动中打开Form_Load
字段。server
的生命周期内使用您认为合适的Form
个活动。您可能会或可能不必担心并发性,但这是另一个问题的问题。server.Dispose()
活动中致电Dispose
。实质上,
class main : Form
{
private TftpServer server;
public main()
{
InitializeComponent();
this.Load += main_Load;
server = new TftpServer();
server.OnReadRequest += new TftpServerEventHandler(server_OnReadRequest);
server.OnWriteRequest += new TftpServerEventHandler(server_OnWriteRequest);
}
private void main_Load(object sender, EventArgs e)
{
server.Start();
}
private void server_OnReadRequest(/* I wasn't sure of the arguments here */)
{
// use the read request: give or fetch its data (depending on who defines "read")
}
private void server_OnWriteRequest(/* I wasn't sure of the arguments here */)
{
// use the write request: give or fetch its data (depending on who defines "write")
}
protected override void Dispose(bool disposing)
{
if (server != null) // since Dispose can be called multiple times
{
server.Dispose();
server = null;
}
}
}
答案 1 :(得分:3)
问题在于处理服务器正在关闭它。请记住,使用只是语法糖。以下两个代码块实际上是等价的:
var foo = new Foo();
try
{
foo.Do();
}
finally
{
foo.Dispose();
}
using (var foo = new Foo())
{
foo.Do();
}
你可以很好地阻止主线程在控制台应用程序中退出,但在Forms应用程序中它是不同的。问题不在于您需要通过执行某种阻塞操作来保持线程在使用中。这将是不好的,行为将锁定您的表单应用程序。问题是你不想使用。您希望在启动服务器时启动它,然后在应用程序退出时或在停止单击时使用Dispose()显式处理它。
答案 2 :(得分:1)
在控制台应用程序中,您的TftpServer
实例正在侦听,直到线程退出时才会按下Console.Read()
在Console.Read()
不等待的表单应用中,using
块结束,导致您的服务器实例超出范围。
所以你并没有完全滥用using
,而是预期用途根本没有帮助你。看一下使用task parallel library让一些后台任务异步运行。
答案 3 :(得分:1)
一个小注释也可以作为答案,你可以在这里使用一个使用块,你只需将它放在你的主函数中:
...(make your form and stuff)
using (var server = new TftpServer())
{
server.OnReadRequest += new TftpServerEventHandler(server_OnReadRequest);
server.OnWriteRequest += new TftpServerEventHandler(server_OnWriteRequest);
server.Start();
Application.Run(yourFormHere); //This blocks until the form is closed
}
我忘记提及的另一个选项是在表单中覆盖Dispose。你可能想要这样做。使用此选项,您可以保证您的服务器将被处理掉(禁止某些事件阻止它以任何方式处置[即内存不足])