我正在用 C# (.net 3.5) 编写一个应用程序,我有一个关于类设计的问题:
我想创建一个访问文件(读、写)并将其内容提供给该类的用户(实例化器)的类。实例上最常见的操作是从文件中检索某个值。实际的读写(io)操作非常昂贵,所以我想将文件数据保存在内存中并让所有实例访问这些数据。该类位于同时从各种应用程序中使用的程序集中,所以我想我应该担心线程安全。
关于线程安全和单元可测试性,我该如何设计(对于单元测试,必须使用与操作代码不同的输入文件)?任何帮助是极大的赞赏。
我正在用 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);
}
}
}
关于线程安全:线程安全不是问题,除非单个应用程序中的多个线程同时引用您的类的同一个实例。除非您的类包含在进程外服务器中,否则多个应用程序无法同时引用同一个实例。因此,您可能会看到的冲突将来自文件共享违规而不是线程问题(换句话说,类的不同实例试图读取和写入同一个文件)。是的,您必须设计代码以适当地处理文件共享。
使类可单元测试的一种方法是在构造函数中为类提供流,而不是让类直接访问文件。然后单元测试可以提供内存流,例如,而不是提供文件流。