FileStreamを入力として受け取るメソッドがあります。このメソッドはforループ内で実行されています。
private void UploadFile(FileStream fileStream)
{
var stream = GetFileStream();
// do things with stream
}
FileStreamを作成して返す別のメソッドがあります。
private FileStream GetFileStream()
{
using(FileStream fileStream = File.Open(myFile, FileMode.Open))
{
//Do something
return fileStream;
}
}
現在、返されたFileStreamにアクセスしようとすると、最初のメソッドがObjectDisposedException
をスローします。おそらく、ストリームを適切に破棄するために "using
"を使用しているため、すでに閉じられているためです。
「using」を使用せず、代わりに次のように使用する場合、FileStreamは開いたままで、ループの次の反復(同じファイルで動作)は、ファイルがすでに使用中であることを示す例外をスローします。
private FileStream GetFileStream()
{
FileStream fileStream = File.Open(myFile, FileMode.Open);
//Do something
return fileStream;
}
finally
のストリームを閉じるtry-finallyブロックを使用すると、ObjectDisposedException
もスローされます。
効果的にファイルストリームを返して閉じる方法は?
メソッドからIDisposable
を返す場合、それを破棄する責任を呼び出し元に任せています。したがって、ストリームの使用全体を囲んでusing
ブロックを宣言する必要があります。この場合、おそらくUploadFile
呼び出しにまたがります。
using (var s = GetFileStream())
UploadFile(s);
問題は、GetFileStream()
メソッドを終了するとすぐにFileStreamオブジェクトが破棄され、使用できない状態になることです。他の回答がすでに示しているように、そのメソッドからusing
ブロックを削除し、代わりにこのメソッドを呼び出すコードをusing
ブロックで囲む必要があります。
_private FileStream GetFileStream()
{
FileStream fileStream = File.Open(myFile, FileMode.Open);
//Do something
return fileStream;
}
using (var stream = GetFileStream())
{
UploadFile(stream);
}
_
しかし、私はこれをさらに一歩進めたいと思います。ずさんなプログラマーがusing
ブロックなしでメソッドを呼び出す場合、または少なくとも何らかの方法で結果を呼び出し側に強く示す場合から、GetFileStream()
によって作成されたストリームを保護する方法が必要です。このメソッドのusing
ブロックで囲む必要があります。したがって、私はこれをお勧めします:
_public class FileIO : IDisposable
{
private FileStream streamResult = null;
public FileStream CreateFileStream(string myFile)
{
streamResult = File.Open(myFile, FileMode.Open);
//Do something
return streamResult;
}
public void Dispose()
{
if (streamResult != null) streamResult.Dispose();
}
}
using (var io = FileIO())
{
var stream = io.CreateFileStream(myFile);
// loop goes here.
}
_
このために、必ずしもまったく新しいクラスを作成する必要はありません。 IDisposableコードを追加するだけで、このメソッドに適切なクラスが既にある場合があります。主なことは、このコードをIDisposable
ブロックでラップする必要があるという他のプログラマへのシグナルとしてusing
を使用できることです。
さらに、これにより、クラスを変更してループの前にIDisposableオブジェクトを1回作成し、ループの最後に破棄する必要があるすべてを新しいクラスインスタンスに追跡させることができます。
開いているファイルストリームを返す必要があるメソッドがある場合、そのメソッドを呼び出す前にストリームを破棄できないため、そのメソッドのすべての呼び出し元は、返されたストリームを破棄する必要があります。