Не уверен, правильно ли я использую «использование» С# в приложении tftp.

StackOverflow https://stackoverflow.com//questions/25070454

  •  26-12-2019
  •  | 
  •  

Вопрос

Я пытаюсь использовать этот предварительно созданное приложение tftp-сервера C# с моей формой Windows C#.В примере сервера автора, который отлично работает, он использует консольное приложение.Когда я пытаюсь перенести его пример консоли в свое приложение формы, это не работает (нет ошибок, просто не подключается), и я считаю, что моя проблема заключается в операторе «использование»:

using (var server = new TftpServer())
{
    server.OnReadRequest += new TftpServerEventHandler(server_OnReadRequest);
    server.OnWriteRequest += new TftpServerEventHandler(server_OnWriteRequest);
    server.Start();
    Console.Read();
}

Не уверен, правильно ли я понимаю, но я верю, что Console.Read() блокирует выход приложения.Если это так, как бы я реализовал эквивалент с помощью приложения формы.Я просто не могу усвоить "использование".Извините, я новичок в С#.

Это было полезно?

Решение

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

Из-за этого вы не можете использовать эквивалент Console.Read() отложить исполнение using удаления до тех пор, пока пользователь не запросит его.Если бы вы это сделали, ваша форма просто не отвечала бы.

Однако вам повезло!А using блок в C# — это не что иное, как синтаксический сахар, позволяющий не забыть вызвать IDisposable.Dispose() после того, как вы закончите работу с объектом.Таким образом, эквивалентом этого в проекте Forms может быть просто сохранение server объект в поле всего класса, а затем вызывая server.Dispose() на, скажем, Button.Click событие.Это, конечно, только пример.Вы также можете сделать это на Form.Closing если бы это казалось более уместным.

Высокий уровень, вы хотите сделать что-то вроде этого:

  1. Объявите поле в классе формы TftpServer server;.
  2. Зарегистрируйте Load мероприятие и все, что вам нужно для вашего server для работы в вашем конструкторе.
  3. Откройте свой server поле в Form_Load событие.
  4. Использовать serverсобытия, которые вы считаете столь подходящими в течение жизни вашего Form.Возможно, вам придется беспокоиться о параллелизме, а может и нет, но это уже другой вопрос.
  5. Вызов 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;
        }
    }
}

Другие советы

Проблема в том, что удаление сервера — это то, что его закрывает.Имейте в виду, что использование — это всего лишь синтаксический сахар.Следующие два фрагмента кода [практически] эквивалентны:

var foo = new Foo();
try
{
   foo.Do();
}
finally
{
   foo.Dispose();
}

using (var foo = new Foo())
{
   foo.Do();
}

Вы можете заблокировать выход основного потока в консольном приложении, но в приложении Forms все по-другому.Проблема не в том, что вам нужно удерживать поток внутри использования, выполняя какую-то операцию блокировки.Это было бы плохо, и такое поведение привело бы к блокировке вашего приложения форм.Проблема в том, что вы не хотите использовать using.Вы хотите обновить его при запуске сервера, а затем, при выходе из приложения или при остановке, явно удалить его с помощью Dispose().

В консольном приложении ваш TftpServer экземпляр прослушивает до тех пор, пока поток не завершится, что происходит только после нажатия клавиши, которая обнаруживается Console.Read()

В вашем приложении форм это Console.Read() не ждет, и поэтому using блок завершается, и это приводит к тому, что экземпляр вашего сервера выходит из области видимости.

Так что вы не совсем злоупотребляете using а скорее предполагаемое использование вам совсем не помогает.Посмотрите, как использовать параллельная библиотека задач чтобы некоторые фоновые задачи выполнялись асинхронно.

Небольшая заметка, которая одновременно служит и ответом. мог используйте здесь блок using, вы просто помещаете его в свою основную функцию:

...(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 в вашей форме.Вы, вероятно, хотите это сделать.С помощью этой опции вы гарантированно будете удалены с вашего сервера (за исключением каких-либо событий, которые помешали бы его удалению в любом случае [т.не хватает памяти])

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top