Можно ли передавать поток по нескольким методам?

У меня есть интерфейс, определяемый как:

public interface IClientFileImporter
{
    bool CanImport(Stream stream);
    int Import(Stream stream);
}

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

Мой вопрос в том, нормально ли проходить такой поток, пока я его никогда не закрываю? Каждый метод должен был бы отвечать за сброс потока в позицию 0, если это необходимо, но есть ли другие потенциальные проблемы (кроме безопасности потоков)? Этот код действительно пахнет, ИМО, но я не уверен в лучшем способе сделать это.

Ответ 1

Чтобы предотвратить изменение базового потока, создайте поток обертки, который происходит из Stream и пересылает только безопасные вызовы в обернутый поток. Кроме того, не принимайте методы Import/CanImport reset позицию потока. Вызывающий из этого метода должен reset передать поток в действительное состояние, прежде чем передать его в Import/CanImport.

Ответ 2

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

Ответ 3

Это не должно быть проблемой.

Хотя я бы, вероятно, немного изменил структуру:

public interface IClientFileImporter
{
    int Import(Stream stream);
}

Тогда у меня был бы метод импорта return -1, если он не смог. Может сделать ваш другой код немного проще.

Ответ 4

Прекрасно передавать один и тот же поток нескольким методам.

Остерегайтесь потоков, не требующих поиска, - есть потоки, в которых вы не можете reset. У Андре Локера есть хороший совет, чтобы обернуть Stream, поэтому методы CanImport не испортили реальный поток.

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

Ответ 5

Если вы беспокоитесь о передаче потока, потому что вы можете запустить внешний код, который может быть ненадежным, лучше всего сделать новый поток readonly и передать его так, чтобы внешний код не мог меняться содержимое файла, пока вы не уверены, что хотите их оставить.

public class ReadonlyStream : Stream
{
    public ReadonlyStream(Stream baseStream)
    {
        ownerStream = baseStream;
    }

    private Stream ownerStream;

    public override bool CanWrite
    {
        get { return false; }
    }

    public override int Write(byte[] bits, int offset, int count)
    {
        throw new InvalidOperationException();
    }

    // Other code ommitted
}