2013-12-11 4 views
5

Я попытался передать поток в качестве аргумента, но я не уверен, какой путь является «лучшим», поэтому хотел бы услышать ваше мнение/предложения по моему образцу кодаКаков наилучший способ передать поток

Я лично предпочитаю варианты три, но я видел, как это делается в другом месте.

Вариант 1 подходит для небольших потоков (и потоки с известным размером)

варианта 2_1 и 2_2 всегда будет оставить «Левша» в сомнении о том, кто несет ответственность за утилизацию/закрытия.

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

ответ

2

Вариант 2_2 - это стандартный способ решения проблемных ресурсов.

Ваш SomeTestClass экземпляр просит продюсера для потока - то SomeTestClassвладеет поток и отвечает за очистку.

Варианты 3 и 2_1 полагаются на другой объект для очистки ресурса, принадлежащего SomeTestClass, - это ожидание может не выполняться.

Вариант 1 - это копирование содержимого потока в другой поток - я не вижу никаких преимуществ при этом.

+0

Вариант 3 просто использует «MemoryStream» как средство, позволяющее преобразовать поток в массив байтов. - Таким образом, это не вопрос разбора потока контента другому потоку. –

+0

Итак, чтобы быть ясным; если вы попросили ввести «void HandleStream (поток потока)»; вы предположили бы, что ваша реализация не несет ответственности за закрытие/удаление потока? –

+0

@JakobDyrby - Тем не менее, вариант 3 читается из «Потока», записывается в «MemoryStream» и преобразуется в 'byte []'. Почему бы просто не читать из «Потока» и использовать буфер? – dcastro

0

Pass вокруг IStream и есть где-либо поток берет свое начало реализации IDisposable. Ответственность за удаление потока лежит на объекте, который его создал.

+0

Итак, объект FileInfo должен нести ответственность за закрытие потока после "fi.OpenRead()" Но это не так? –

+0

См. Комментарий @ dcastro: «Как правило, ключевое слово является собственностью. Тот, кто владеет экземпляром IDisposable, несет ответственность за его закрытие». –

0

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

Что касается вашей реализации, я рекомендую вам идти с опцией # 2:

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

Что касается Возражать жизни, это мое убеждение, что:

  • реализации должен быть последовательным в том, как он обрабатывает вызов Dispose
  • Ваше решение будет более гибким, если IStreamHandler не позвонил Dispose (сейчас Вы можете обработчики цепи вместе так же, как вы бы в Unix труб)

НЕЗАВИСИМЫЕ РЕШЕНИЯ

Построение решения трубопровода может быть интересно, но это также стоит отметить, что есть существующие продукты на рынок:

ДОПОЛНИТЕЛЬНЫЕ УКАЗАНИЯ

Существует проблема дизайна, связанная с вашем предложил Вариант 2:

void Process(Stream stream); 

В Unix Pipes вы можете цепь ряда приложений вместе взяв вывод одной программы и сделав ее входом другой. Если вы собираетесь построить аналогичное решение, используя Вариант 2, у вас возникнут проблемы, если вы используете несколько обработчиков и ваши данные. Stream только вперед (т. Е. stream.CanSeek=False).

+0

Спасибо! Я прочитаю эту схему дизайна. Но сейчас; не могли бы вы рассказать о том, кто, по вашему мнению, несет ответственность за ликвидацию. Должен ли я использовать интерфейс, как показано в опции 2_1 или в опции 2_2? –

+0

Я бы пошел с: DoOption2_2. Что еще более важно: ** (1) ** быть в соответствии с вашей реализацией и ** (2) ** гарантировать, что все ресурсы будут выпущены в случае непредвиденного исключения. – Pressacco

Смежные вопросы