Progettazione della classe: avvolgere un file di dati in una classe per quanto riguarda la sicurezza del thread e la testabilità

StackOverflow https://stackoverflow.com/questions/208184

Domanda

Sto scrivendo un'app in C # (.net 3.5) e ho una domanda sul design della classe:

Mi piacerebbe creare una classe che acceda a un file (lettura, scrittura) e fornisca il suo contenuto agli utenti (istanziatori) della classe. L'operazione più comune su un'istanza sarà quella di recuperare un determinato valore dal file. Le operazioni di lettura e scrittura (io) effettive sono costose, quindi mi piacerebbe conservare i dati del file in memoria e consentire a tutte le istanze di accedere a questi dati. La classe si trova in un assembly che viene utilizzato contemporaneamente da varie applicazioni, quindi credo che dovrei preoccuparmi della sicurezza del thread.

Come posso progettare questo riguardo alla sicurezza del filo e alla testabilità dell'unità (per i test unitari, è necessario utilizzare file di input diversi rispetto al codice operativo)? Qualsiasi aiuto è molto apprezzato.

È stato utile?

Soluzione

Innanzitutto, fai in modo che la tua classe implementi un'interfaccia appropriata. In questo modo, i clienti possono testare il loro comportamento senza la necessità di file reali.

Testare la sicurezza del thread è difficile - non ho mai visto nulla di veramente utile su quel fronte, anche se questo non vuol dire che gli strumenti non siano là fuori.

Per testare l'unità della tua classe, suggerirei che, se possibile, dovrebbe funzionare con un flusso generale piuttosto che solo con un file. Quindi è possibile incorporare diversi file di test nell'assieme di test e fare riferimento a essi con GetManifestResourceStream . L'ho fatto diverse volte in passato, con grande successo.

Altri suggerimenti

Usa ReaderWriterLock , che ritengo adatto la descrizione del problema.

Segue un'implementazione rapida e sporca. L'acquisizione di blocchi potrebbe essere più intelligente, come provare più volte prima del salvataggio ecc. Ma ottieni il punto:

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);
     }
   }
}

Per quanto riguarda la sicurezza dei thread: la sicurezza dei thread non è un problema a meno che più thread all'interno di una singola applicazione si riferiscano contemporaneamente alla stessa istanza della classe. A meno che la classe non sia contenuta in un server fuori processo, non è possibile che più applicazioni facciano riferimento contemporaneamente alla stessa istanza. Pertanto, i conflitti che probabilmente vedrai provengono da violazioni della condivisione di file piuttosto che da problemi di threading (in altre parole, diverse istanze della classe che tenta di leggere e scrivere lo stesso file ). E sì, è necessario progettare il codice per gestire la condivisione dei file in modo appropriato.

Un modo per rendere testabile l'unità di classe è fornire alla classe un flusso nel costruttore anziché avere la classe di accedere direttamente a un file. Quindi il test unitario può fornire un flusso di memoria, ad esempio, invece di fornire un flusso di file.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top