Дизайн класса: Заключение файла данных в класс с точки зрения безопасности потока и тестируемости - PullRequest
0 голосов
/ 16 октября 2008

Я пишу приложение на C # (.net 3.5) и у меня есть вопрос по поводу дизайна класса:

Я хотел бы создать класс, который обращается к файлу (чтение, запись) и предоставляет его содержимое пользователям (инстанциаторам) класса. Наиболее распространенной операцией в экземпляре будет получение определенного значения из файла. Реальные операции чтения и записи (io) очень дороги, поэтому я хотел бы сохранить данные файла в памяти и позволить всем экземплярам получить доступ к этим данным. Класс находится в сборке, которая используется из разных приложений одновременно, так что, думаю, мне следует беспокоиться о безопасности потоков.

Как мне спроектировать это с точки зрения безопасности потоков и тестируемости модулей (для модульных тестов должны использоваться другие входные файлы, чем в рабочем коде)? Любая помощь с благодарностью.

Ответы [ 3 ]

1 голос
/ 16 октября 2008

Используйте 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);
     }
   }
}
1 голос
/ 16 октября 2008

Во-первых, заставьте ваш класс реализовать соответствующий интерфейс. Таким образом, клиенты могут проверить свое поведение, не нуждаясь в реальных файлах вообще.

Тестирование безопасности потоков сложно - я никогда не видел ничего действительно полезного на этом фронте, хотя нельзя сказать, что инструментов там нет.

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

0 голосов
/ 16 октября 2008

Относительно безопасности потоков: Безопасность потоков не является проблемой, если только несколько потоков в одном приложении не будут одновременно ссылаться на один и тот же экземпляр вашего класса. Если ваш класс не содержится на сервере вне процесса, несколько приложений не смогут одновременно ссылаться на один и тот же экземпляр. Поэтому конфликты, которые вы, скорее всего, увидите, будут вызваны нарушениями общего доступа к файлам, а не проблемами многопоточности (другими словами, разные экземпляры класса пытаются прочитать и написать один и тот же файл ). И да, вы должны разработать свой код для надлежащего обмена файлами.

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

...