类设计:在线程安全性和可测试性方面,将数据文件封装成一个类

本文关键字:封装 文件 数据 一个 线程 可测试性 安全性 方面 | 更新日期: 2023-09-27 17:47:47

我正在用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);
     }
   }
}

关于线程安全:线程安全不是问题,除非单个应用程序中的多个线程将同时引用类的同一实例。除非您的类包含在进程外服务器中,否则多个应用程序无法同时引用同一实例。因此,您可能看到的冲突将来自文件共享冲突,而不是线程问题(换句话说,类的不同实例试图读取和写入同一文件)。是的,您必须设计适当的代码来处理文件共享。

使类单元可测试的一种方法是在构造函数中为类提供流,而不是让类直接访问文件。然后,单元测试可以提供内存流,而不是提供文件流。