3

I'm writing an API that exports data to a Stream:

public interface IExporter<in T>
{
    Task ExportAsync(IEnumerable<T> inputs, Stream output);
}

Probably the various IExporter implementations will use a form of TextWriter/StreamWriter but I don't want to enforce it on the interface.

The main problem with the usage of StreamWriter is that by default it closes the underlying stream (I know that there's a constructor but it requires bufferSize, I could subclass StreamWriter but I don't like it either).

Shall I simply "own" the Stream in my IExporter implementation (and dispose it by disposing my StreamWriter) or are there any better ways to handle this problem?

aghidini
  • 2,855
  • 5
  • 29
  • 32
  • @HansPassant I don't understand, I can use the `using` keyword or am I missing something? e.g. `using (var stream = ...) { await _exporter.ExportAsync(..., stream); }`? – aghidini Nov 11 '16 at 14:07
  • 1
    You can, but you demand that the client code uses *await*. And it is going to work rather poorly when it doesn't. It just isn't necessary, an Export method will be assumed to consume the entire stream, not just part of it. So the stream object is always useless after it completed, it might as well dispose it and now it never goes wrong. Otherwise the core reason why .NET streams always transfer ownership. – Hans Passant Nov 11 '16 at 14:14
  • 1
    @HansPassant, with this approach, I'm not able to perform an export multiple times into one stream. What if I want to write the data sequentially? I cannot assume that the `Export()` method will consume the whole stream. – dymanoid Nov 11 '16 at 14:24

2 Answers2

4

The caller should be responsible for the resources. The called method has no information (neither should it have any) whether the provided object will be used by others. So it's a bad decision to dispose any objects provided to a method (e.g. what if this object's lifetime is managed by a Dependency Injection container?)

dymanoid
  • 14,771
  • 4
  • 36
  • 64
  • I agree, that's how I started to write my code. However by using internally a `StreamWriter` I don't like to *not* Dispose them to avoid closing the Stream. Shall I simply use the other constructor https://msdn.microsoft.com/en-us/library/gg712853(v=vs.110).aspx (or use a custom StreamWriter that does not close the underlying stream)? – aghidini Nov 11 '16 at 14:02
  • 1
    @aghidini, it's up to you of course. If you have any custom `Stream`-derived implementations, use them. The `leaveOpen` flag is a good solution too. Anyone who will implement your interface should be aware that they are not allowed to dispose the provided stream. And there are no problems with `async` anyway: you can `await` a method inside an `using` statement, and the c# compiler manages that for you. – dymanoid Nov 11 '16 at 14:17
  • Something to keep in mind re: an earlier comment *"If you have any custom Stream-derived implementations, use them. The leaveOpen flag is a good solution too. Anyone who will implement your interface should be aware that they are not allowed to dispose the provided stream"*... try to follow the [SOLID Design Principles](http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod) and make sure that the derived type does not change the intended behavior of the base class. – Pressacco Nov 11 '16 at 14:29
1

In this scenario, I think it boils down to personal preference. Generally speaking I try to follow these guidelines:

  1. be consistent in the application's design
  2. if an object allocates a resource (e.g. new), then it should also be responsible for releasing it (e.g Dispose)

Additional Reading

Community
  • 1
  • 1
Pressacco
  • 2,815
  • 2
  • 26
  • 45