2008-10-16 4 views
0

Я пишу приложение в C# (.NET 3.5) и у меня есть вопрос о дизайне класса:дизайн Класс: Завершая файл данных в класс по безопасности потоков и контролируемости

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

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

ответ

1

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

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

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

+0

Не могли бы вы предоставить более подробную информацию? Я все еще не знаю, как создать класс. Как должен выглядеть интерфейс? Только GetFilePortionX/SetFilePortionY? Как я могу избежать повторной загрузки filedata с каждой установкой. Потерпите меня, я начинаю и действительно застрял на этом. – Mats 2008-10-16 12:01:02

+0

А, я не заметил, что вам нужно писать, а также читать. Это боль в плане тестирования - хотя вы можете использовать MemoryStream для его поддержки. Что касается интерфейса, выясните, что нужно клиентам. Является ли Get/SetPortion всем? Если это так, это ваш интерфейс. – 2008-10-16 14:13:11

0

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

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

1

Используйте 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); 
    } 
    } 
}