Barry said:
One already has 'File.Open' and related methods which provide the
appropriate arguments to the FileStream constructor.
But on the other hand - what's the benefit from using this approach?
File.Open doesn't have an ambiguous meaning. It's perfectly clear from
the name that a file will be opened if no exceptions are thrown. The
problem is that it's on a separate class, which is fine, but how would
one know to look at the File class if they're currently interested in
the FileStream class. It makes more sense to add it to the FileStream
class as well. Consider the following lines of code.
FileStream stream = new FileStream("foo.txt");
FileStream stream = FileStream.Open("foo.txt");
Without knowing anything about a FileStream what can we say about these
lines of code? The only thing we can say for certain about the first
line is that stream can be used to read/write data in the foo.txt file.
We can say more about the second. Not only can it read/write to
foo.txt, but it is *ready* to do so since the method clearly indicates
that the stream is open when it's returned.
But, that's not why I think it was a poor design choice. I think it's
a poor design choice because a constructor that throws an IOException
has a complex operation embedded in it. That contradicts the following
guideline.
"Do minimal work in the constructor. Constructors should not do much
work other than to capture the constructor parameters. The cost of any
other processing should be delayed until required." --Framework Design
Guidelines by Cwalina & Abrams.
If
one calls the static method rather than using the constructor, what's
been gained over the losses: extra complexity, the divorce between where
the object is constructed (the static method) and the actual object
implementation, and the extra mode on the file stream?
I don't see where there's extra complexity. In fact, from the callers
perspective the interface would be more self describing and thus
simpler to use!
You wouldn't necessarily have to move logic around to accomodate the
factory method. Just make the constructor private and have the factory
call that if you like.
Using the static factory method approach it would still be impossible
to reopen a closed stream since there wouldn't be an instance method
there to do it.
Also, won't all
streams now need this Open() method?
Yep. That's how most of the objects that acquire resources in the
System.Net and System.Data namespaces work. Though, in those examples
they're usually instance methods.
What do you do when you get a
stream from elsewhere, like a NetworkStream from a socket? Do you need
to open that too? If not, where does all this documentation go?
I'd say no especially if the documentation on the stream indicated that
a caller can assume it's open if the Close method hasn't been
previously called. That's pretty much how it works now. The same
semantics can be acheived with a static factory method.