2013-12-11 18 views
5

Próbowałem przekazać strumień jako argument, ale nie jestem pewien, która droga jest "najlepsza", dlatego chciałbym usłyszeć Twoją opinię/sugestie na temat mojej próbki koduJaki jest najlepszy sposób przekazania strumienia wokół numeru

Ja osobiście wolę opcje trzy, ale nowsze widziałem, jak to robiono w ten sposób gdziekolwiek indziej.

Wariant 1 jest dobre dla małych strumieni (i strumieni o znanej wielkości)

Option 2_1 i 2_2 zawsze opuścić „zakręt” wątpliwości, kto jest odpowiedzialny za zbywanie/zamykania.

public interface ISomeStreamHandler 
{ 
    // Option 1 
    void HandleStream(byte[] streamBytes); 

    // Option 2 
    void HandleStream(Stream stream); 

    // Option 3 
    void HandleStream(Func<Stream> openStream); 
} 


public interface IStreamProducer 
{ 
    Stream GetStream(); 
} 



public class SomeTestClass 
{ 
    private readonly ISomeStreamHandler _streamHandler; 
    private readonly IStreamProducer _streamProducer; 

    public SomeTestClass(ISomeStreamHandler streamHandler, IStreamProducer streamProducer) 
    { 
     _streamHandler = streamHandler; 
     _streamProducer = streamProducer; 
    } 

    public void DoOption1() 
    { 
     var buffer = new byte[16 * 1024]; 
     using (var input = _streamProducer.GetStream()) 
     { 
      using (var ms = new MemoryStream()) 
      { 
       int read; 
       while ((read = input.Read(buffer, 0, buffer.Length)) > 0) 
       { 
        ms.Write(buffer, 0, read); 
       } 
       _streamHandler.HandleStream(ms.ToArray()); 
      } 
     } 
    } 

    public void DoOption2_1() 
    { 
     _streamHandler.HandleStream(_streamProducer.GetStream()); 
    } 

    public void DoOption2_2() 
    { 
     using (var stream = _streamProducer.GetStream()) 
     { 
      _streamHandler.HandleStream(stream);  
     } 
    } 


    public void DoOption3() 
    { 
     _streamHandler.HandleStream(_streamProducer.GetStream); 
    } 
} 

Odpowiedz

2

Opcja 2_2 to standardowy sposób postępowania z zasobami rozporządzalnymi.

instancję SomeTestClass pyta producent dla strumienia - wtedy SomeTestClassposiada strumień i jest odpowiedzialny za sprzątanie.

Opcje 3 i 2_1 polegają na innym obiekcie w celu oczyszczenia zasobu należącego do SomeTestClass - to oczekiwanie może nie zostać spełnione.

Opcja 1 to kopiowanie treści strumienia do innego strumienia - nie widzę w tym żadnych korzyści.

+0

Opcja 3 po prostu używa "MemoryStream" jako sposobu, aby móc przekonwertować strumień na tablicę bajtów. - Więc nie jest to kwestia parsowania treści strumienia do innego strumienia. –

+0

Aby było jasne; jeśli zostaniesz poproszony o wstawienie "void HandleStream (Stream stream);" zakładasz, że twoja implementacja nie była odpowiedzialna za zamknięcie/usunięcie strumienia? –

+0

@JakobDyrby - Mimo wszystko, Opcja 3 czyta z "Stream", pisząc do 'MemoryStream' i konwertując na' byte [] '. Czemu po prostu nie czytać z 'Stream' i nie używać bufora? – dcastro

0

przechodzące w IStream i mają w których historii strumień pochodzi realizacji IDisposable. Odpowiedzialność za pozbycie się strumienia spoczywa na obiekcie, który go utworzył.

+0

Tak więc obiekt FileInfo, jest odpowiedzialny za zamknięcie strumienia po "fi.OpenRead()" Ale tak nie jest? –

+0

Zobacz komentarz @ dcastro: "Z reguły słowo kluczowe to własność." "Kto jest właścicielem instancji IDisposable, jest odpowiedzialny za jej zamknięcie." –

0

Może nie zdajesz sobie z tego sprawy, ale próbujesz wdrożyć wzór projektowania rurociągu . Jako punkt wyjścia, należy rozważyć przyjrzeniu:

W odniesieniu do implementacji, polecam, aby iść z opcja nr 2:

public interface IStreamHandler 
{ 
    void Process(Stream stream); 
} 

W odniesieniu do sprzeciwu całe życie, to jest moje przekonanie, że:

  • realizacji powinien być spójny pod względem obsługi wywoływania, dlatego twoje rozwiązanie będzie bardziej elastyczne, jeśli IStreamHandler nie zadzwoni pod numer Dispose (n OW można koparki łańcuchowe razem podobnie jak byś w rurach Unix)

TRZECICH ROZWIĄZANIA

Budowanie rozwiązania rurociągu może być zabawne, ale warto również zauważyć, że istnieją istniejące produkty na Rynek:

DODATKOWA

Jest to kwestia projektowania związane z proponowanego Opcja 2:

void Process(Stream stream); 

W Unix Pipes możesz łańcuch szereg zastosowań razem przez pobranie wyjścia jednego programu i wprowadzenie go jako wejścia innego. Jeśli chcesz zbudować podobne rozwiązanie przy użyciu opcji Opcja 2, będą występowały problemy, jeśli używasz wielu procedur obsługi, a dane będą tylko Stream (tj. stream.CanSeek=False).

+0

Dziękujemy! Przeczytam ten wzorzec projektowy. Ale teraz; Czy mógłbyś wyjaśnić, kto Twoim zdaniem ma obowiązek zamknąć misję? Czy powinienem używać interfejsu, jak pokazano w opcji 2_1 lub w opcji 2_2? –

+0

Chciałbym iść z: DoOption2_2. Co ważniejsze: ** (1) ** jest spójne z twoją implementacją i ** (2) ** zapewnia, że ​​wszystkie zasoby zostaną zwolnione, jeśli wyjątek zostanie zgłoszony nieoczekiwanie. – Pressacco