Как правильно утилизировать asyc NetworkStream

Я пытаюсь избавиться от NetworkStream после того, как он закончил писать. Я пытался обернуть поток в using() вот так:

using (NetworkStream stream = client.GetStream())
{
     foreach (byte[] command in fadeSceneOut)
     {
          if (stream.CanWrite)
          {
               stream.BeginWrite(command, 0, command.Length, new AsyncCallback(SendCallback), stream);
          }
     }
}

Но я получаю System.ObjectDisposedException указав, что объект уже был удален и не может быть доступен в моем обратном вызове, куда я отправляю EndWrite():

private static void SendCallback(IAsyncResult ar)
{
    try
    {
        NetworkStream stream = (NetworkStream)ar.AsyncState;
        stream.EndWrite(ar);
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
    }
}

Насколько я понимаю, поток не будет удален, пока исполнение не покинет using блок после того, как все команды были записаны в поток. Очевидно, я что-то здесь не так, может кто-нибудь посоветовать правильный подход?

Редактировать: включены await подход:

static void Main(string[] args)
{
     Task.WaitAll(Run());
}

public static async Task Run()
{
    // Get a scene
    var scene = GrabSceneFromUser();

    // Get scene commands
    var fadeSceneIn = LightSwarmHelper.BuildSceneCommands(scene);
    var fadeSceneOut = LightSwarmHelper.BuildSceneCommands(scene, false);

    // Send commands to device
    using (TcpClient client = new TcpClient(ConfigurationManager.AppSettings["Host"], Convert.ToInt32(ConfigurationManager.AppSettings["Port"])))
    {
        using (NetworkStream stream = client.GetStream())
        {
            foreach (byte[] command in fadeSceneOut)
            {
                if (stream.CanWrite)
                {
                    await stream.WriteAsync(command, 0, command.Length); //stream.BeginWrite(command, 0, command.Length, new AsyncCallback(SendCallback), stream);
                }
            }
        }
    }
}

2 ответа

Поскольку вызов stream.BeginWrite(...) не является блокирующим, блок using будет оставлен до завершения операции записи, отсюда и исключение. Правильное место для удаления потока будет в функции обратного вызова.

Ответ Стефана правильный и указывает на основную причину. Вы должны принять это. Я добавлю еще один способ решения проблемы:

Этот код устарел, используйте await. Затем вы создаете неограниченное количество одновременных отправок. Это может легко истощить ресурсы. Это может даже привести к коррупции, не уверен.

Выполните посылку последовательно. Это очень легко и естественно с ожиданием.

if (stream.CanWrite)

Это не продумано... CanWrite всегда будет возвращать true, а если он возвращает false, вы просто ничего не делаете и скрываете ошибку.

Другие вопросы по тегам