Как я могу использовать «using» в C# без получения «InvalidOperationException»?

Я пытаюсь ответить на следующий код, который отлично работает

TcpClient oC = new TcpClient(ip, port);
oC = new TcpClient(ip, port);
StreamReader messageReader;

try {
   messageReader = new StreamReader(oC.GetStream(), Encoding.ASCII);
   reply = messageReader.ReadLine();
}

с участием

try {
   using (messageReader = new StreamReader(oC.GetStream(), Encoding.ASCII))
   {
       reply = messageReader.ReadLine();
   }
}

Но у меня есть InvalidOperationException поговорка

Операция не разрешена на неподключенных розетках.

В чем проблема и как ее исправить?

Подробнее: у меня есть oc.Connect до этого кода, поэтому я подключен, и когда он хочет, чтобы его использовали в первый раз, все работает нормально, только после этого я получаю это исключение, я немного поигрался с ним, и теперь Я получил:

Невозможно получить доступ к удаленному объекту. \ R \ nИмя объекта: 'System.Net.Sockets.Socket'.

Ответов (6)

Решение

Повторяю свой комментарий к ответу Джаредса.

Али прокомментировал:

У меня есть oc.Connect до этого, и он отлично работает в первый раз, но во второй раз я также получаю «Невозможно получить доступ к удаленному объекту. \ R \ nИмя объекта: 'System.Net.Sockets.Socket'». - Али (13 минут назад)

Я прокомментировал:

"и это потому, что StreamReader становится владельцем потока, закрывает и удаляет поток, с помощью которого вы его инициируете. В данном случае это NetworkStream TcpClient. Здесь нет необходимости избавляться от StreamReader"

Кроме того, вы объявили messageReader как StreamWriter. Разве это не должно быть StreamReader?

StreamWriter messageReader;

[Исправлено OP]

Еще один совет: лучше всего создать экземпляр объекта в операторе using, а не передавать его. Это может быть не фактической причиной вашего исключения, а из MSDN :

Вы можете создать экземпляр объекта ресурса, а затем передать переменную в оператор using, но это не лучшая практика. В этом случае объект остается в области видимости после того, как элемент управления покидает использующий блок, даже если он, вероятно, больше не будет иметь доступа к своим неуправляемым ресурсам. Другими словами, он больше не будет полностью инициализирован. Если вы попытаетесь использовать объект вне блока using, вы рискуете вызвать исключение. По этой причине, как правило, лучше создать экземпляр объекта в операторе using и ограничить его область действия блоком using.

Так что используйте правильный конструктор .

using (messageReader = 
        new StreamReader(oC.GetStream(), Encoding.ASCII, false, 4096, true))
{
   reply = messageReader.ReadLine();
}

Обратите внимание на последний параметр leaveOpen: и прочтите, что он означает в документации .

Однако IIRC, StreamReader буферизует содержимое из потока (по умолчанию считывается 4096 байт), поэтому, когда вы удалили StreamReader, вы можете быть удивлены, обнаружив, что позиция потока вышла за пределы конца данных, которые вы читать с StreamReader. Позволить StreamReader стать владельцем - это всегда хорошая идея. Разве вы не можете оставить его открытым, пока не прочитаете все данные?

Я думаю, вам не разрешено сначала определять StreamWriter, а затем использовать его с использованием.

Попробуй это:

TcpClient oC = new TcpClient(ip, port);
oC = new TcpClient(ip, port);

try {
   using (StreamWriter messageReader = new StreamReader(oC.GetStream(), Encoding.ASCII))
   {
       reply = messageReader.ReadLine();
   }
}

Попробуйте вызвать oc.Connect перед созданием StreamReader. Пока сокет не подключен, читать нечего и, следовательно, исключение.

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

Редактировать:

Похоже, что происходит то, что вы подключаетесь один раз, а затем либо соединение разрывается, либо объект теряет область видимости. Что вам нужно сделать в этом случае, это, вероятно, перехватить отключение, а также воссоздать сокет, который изначально использовался для подключения к серверу. Как только этот сокет будет удален, вы больше не сможете использовать ту же ссылку, вам придется создать новую ссылку и использовать ее.

У вас есть более полный пример, который вы могли бы опубликовать, который показал бы объем вашего соединения по сравнению с использованием, чтобы мы могли точно видеть, где базовый сокет выбирается GC?