クラス設計:スレッドの安全性とテスト容易性に関して、データファイルをクラスにまとめる
-
03-07-2019 - |
質問
C#(.net 3.5)でアプリを作成していますが、クラス設計について質問があります:
ファイルにアクセス(読み取り、書き込み)し、そのコンテンツをクラスのユーザー(インスタンス化者)に提供するクラスを作成したいと思います。インスタンスで最も一般的な操作は、ファイルから特定の値を取得することです。実際の読み取りおよび書き込み(io)操作は高価であるため、ファイルデータをメモリに保持し、すべてのインスタンスがこのデータにアクセスできるようにします。このクラスは、さまざまなアプリケーションから同時に使用されるアセンブリにあるため、スレッドの安全性について心配する必要があると思います。
スレッドセーフと単体テストの可能性に関してこれをどのように設計しますか(単体テストの場合、操作コードとは異なる入力ファイルを使用する必要があります)?どんな助けも大歓迎です。
解決
まず、クラスに適切なインターフェイスを実装させます。これにより、クライアントは実際のファイルをまったく必要とせずに動作をテストできます。
スレッドの安全性をテストするのは難しい-ツールがそこにないわけではないが、その面で本当に役立つものを見たことがない。
クラスのユニットテストについては、可能であれば、単なるファイルではなく一般的なストリームで動作することをお勧めします。その後、テストアセンブリにさまざまなテストファイルを埋め込み、 GetManifestResourceStream 。私はこれを過去に数回行い、大成功を収めました。
他のヒント
ReaderWriterLock を使用します。問題の説明。
以下は、迅速で汚い実装です。ロックを取得する方が、救済の前に複数回試行するなど、よりスマートになる可能性があります。しかし、ポイントを得ます:
public class MyFooBarClass
{
private static ReaderWriterLock readerWriterLock = new ReaderWriterLock();
private static MemoryStream fileMemoryStream;
// other instance members here
public void MyFooBarClass()
{
if(fileMemoryStream != null)
{
// probably expensive file read here
}
// initialize instance members here
}
public byte[] ReadBytes()
{
try
{
try
{
readerWriterLock.AcquireReaderLock(1000);
//... read bytes here
return bytesRead;
}
finally
{
readerWriterLock.ReleaseReaderLock();
}
}
catch(System.ApplicationException ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
public void WriteBytes(bytes[] bytesToWrite)
{
try
{
try
{
readerWriterLock.AcquireWriterLock(1000);
//... write bytes here
}
finally
{
readerWriterLock.ReleaseWriterLock();
}
}
catch(System.ApplicationException ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
}
スレッドセーフについて:単一のアプリケーション内の複数のスレッドがクラスの同じインスタンスを同時に参照しない限り、スレッドセーフは問題になりません。クラスがアウトプロセスサーバー内に含まれていない限り、複数のアプリケーションが同じインスタンスを同時に参照する方法はありません。したがって、発生する可能性のある競合は、スレッドの問題(つまり、同じ file )。はい、ファイル共有を適切に処理するようにコードを設計する必要があります。
クラスユニットをテスト可能にする1つの方法は、クラスがファイルに直接アクセスするのではなく、クラスにコンストラクターでストリームを提供することです。単体テストは、たとえば、ファイルストリームを提供する代わりに、メモリストリームを提供できます。